4 ms·
Exactly. Pythonic versions: groupBy(fn): {fn(x): x for x in foo} sortBy(fn): sorted(foo, key=fn) countBy(fn): Counter(fn(x) for x in foo) flatt
by quietbritishjim 5y ago
Exactly. Pythonic versions:
groupBy(fn): {fn(x): x for x in foo}
sortBy(fn): sorted(foo, key=fn)
countBy(fn): Counter(fn(x) for x in foo)
flatten: [x for y in foo for x in y]
filter(fn): [x for x in foo if fn(x)]
All the "for x in blah" can seem like a lot of boilerplate for a non-Pythonista, but actually it becomes subconscious once you're used to it and actually helps you feel the structure (a bit like indentation isn't necessary in C but it still helps you to see it).
For compound operations (e.g. merge two lists, filter and flatten), I find the code to be a lot more easier to "feel" than if you'd combined several functional style functions, where you have to read the function names instead of just seeing the structure.
- unishark 5y agoSpeaking of the list and set comprehensions, they also mimic formal mathematical notation e.g. {f(x) | x>0, x in reals} or whatever
- cwilkes 5y agoThat groupBy doesn’t look like it does what you want to do. For example if “def fn(i): return i//2” You probably want to get an output like {0: [0,1]} but you’ll only get a scalar for the value (1) and it will be the last one evaluated. It would be nice if there was a way to do this on one line but you’ll have to do ret=collections.defaultdict(list) For i In foo: ret[fn(i)].append(i) Return ret I suppose it isn’t that bad as it will be in the groupBy method. Or you could add it to a method on a list. I think that’s easier to do with Rust.
- quietbritishjim 5y agoHmm, you're right... that one is actually quite hard to do in a Python-ish way. There is a one liner, just for the record, but it's absolutely horrific code because it redundantly re-evaluates the same conditions over and over: g = {fn(x): [y for y in foo if f(y)==f(x)] for x in foo} As you said, you'd have to use a for loop. I think sometimes people are unnecessarily afraid of for loops in Python (not everything has to fit on one line!) but this is a case it's a pity to take up so many lines. Or, back to square one, probably this is a case it's best just to use itertools groupby (after a sort) after all.
- matsemann 5y ago> All the "for x in blah" can seem like a lot of boilerplate for a non-Pythonista It's not the boilerplate that's the problem, it's that using the same construct for everything doesn't convey its intention. If I see a chain of filter, map, group etc., I instantly know what each part does. I know that filter does a filtering, and then I can look at the function passed to it do know how exactly it's filtering. If I see a list comprehension, I have to first understand if it's filtering or mapping or whatever (or even all at once), before I can grok it.
- formerly_proven 5y agofilter(fn): [x for x in foo if fn(x)] Python has filter(predicate, iterable) -> iterable built in.
- quietbritishjim 5y agoAbsolutely but it's not "Pythonic". Guido said: > About 12 years ago, Python aquired lambda, reduce(), filter() and map(), courtesy of (I believe) a Lisp hacker who missed them and submitted working patches. But, despite of the PR value, I think these features should be cut from Python 3000. ("Python 3000" was the code name for Python 3.) He eventually stepped back from this hard line view but it remains a fact that it's a bit of a historical accident that it's present at all. [1] https://www.artima.com/weblogs/viewpost.jsp?thread=98196 https://www.artima.com/weblogs/viewpost.jsp?thread=98196
- Zababa 5y agoThe thing is, filter is present in almost all languages now while list comprehensions are in Python, Julia and Haskell. Maybe it's not "pythonic", but Python doesn't exist in a vacuum and is influenced by other languages, as proven with the optional typing and the pattern matching. Maybe it's time to review the definition of pythonic?