mahmoud / glom

☄️ Python's nested data operator (and CLI), for all your declarative restructuring needs. Got data? Glom it! ☄️
https://glom.readthedocs.io
Other
1.88k stars 61 forks source link

replicate logic with Switch #268

Closed antoine-gallix closed 9 months ago

antoine-gallix commented 11 months ago

I've tried many forms of spec, but I haven't been able, just by reading the documentation of Switch, to replicate the following logic with it:

def spec(target):
    if target.get("condition", False):
        return target.get("this", None)
    else:
        return target.get("that", None)

data = {"condition": True, "this": "A", "that": "B"}
# spec(data) => 'A'
data = {"condition": True, "that": "B"}
# spec(data) => None
data = {"condition": False, "this": "A", "that": "B"}
# spec(data) => 'B'
data = {"condition": False, "this": "A"}
# spec(data) => None
data = {'this': 'A', 'that': 'B'}
# spec(data) => B
data = {'this': 'A'}
# spec(data) => None

What's the solution?

kurtbrose commented 10 months ago

Here's one approach:

spec = Switch({"condition": T.get("this")}, default=T.get("that"))

Another way to go about it is use something that will always be True to make a default inside the Switch dict:

spec = Switch({"condition": T.get("this"), Val(True): T.get("that")})

You can also use glom.And / glom.Or to achieve what you want through short-circuit logic:

And("condition", T.get("this"), default=T.get("that"))
Or(And("condition", T.get("this")), T.get("that"))

This expression looks most concise to me: And("condition", T.get("this"), default=T.get("that")) -- although it is also 100% valid to embed that spec() function you wrote inside a spec.

Whatever is most readable!

antoine-gallix commented 9 months ago

Thanks!