7 ms·
Not sure what collate is supposed to be, but these idioms are hardly difficult if you're used to Python: - groupBy is itertools.groupBy(lst, fn) - sortBy is j
by smallnamespace 5y ago
Not sure what collate is supposed to be, but these idioms are hardly difficult if you're used to Python:
- groupBy is itertools.groupBy(lst, fn)
- sortBy is just lst.sort(key=fn)
- countBy is collections.Counter(map(fn, lst))
- Sibling comment mentioned flatten, which is just [item for sublist for sublist in lst]
More esoteric needs are usually met by itertools.
- masklinn 5y ago> - sortBy is just lst.sort(key=fn) You mean sorted(). list.sort only works on list and in-place.
- gfaure 5y agoAnnoyingly, itertools is one of those packages in the Python standard library with wordsruntogether-named functions, so it's really known as itertools.groupby instead.
- bobbylarrybobby 5y agoThe real issue is that python doesn’t really make it easy to define anonymous functions. If you want one with more than one line, you need to name it and move its definition outside the point of use. Quite annoying.
- diarrhea 5y agoI always thought of that as a feature.
- mrweasel 5y agoExcessive usage of anonymous functions is a major pain. JavaScript developers for some reason almost refuse to name their functions, even though it would make reading and reusing code much easier. You can make lambdas in Python, but naming function is in my mind very much a "feature".
- tobr 5y agoHm, why is it more important to name a function than, say, an if statement?
- pjmlp 5y agoCode readability, specially if it spans multiple lines and has conditional code into it. Same applies to then and else branches. In a code review I don't what to read a thesis inside of a conditional branch.
- mrweasel 5y agoIf you just have a short one or two lines of code in a callback, maybe it's not so important. Where I have an issue is when you have five nested anonymous functions. Why wouldn't you break those out into named functions? Assuming you have five levels nested if, ignoring the fact that you might be doing something wrong, then you should name those, but that requires you to extract those code paths and put them into separate functions.
- roenxi 5y agoBecause an if statement is very constrained in what it can do. Every if statement has two branches (maybe one is a no-op) and one of them executes. If someone sees an if statement, it is implementing a fork in the code path. A function can do literally anything. Seeing a function call, it hasn't narrowed down the realm of what might be happening even a little bit. "lambda f:" gives away very little information about what is about to happen. "if f:" gives away some information about what is about to happen. Not a perfect rule of thumb, convoluted if statements do exist. But that is why functions are more in need of hints and comments than other control structures.
- chriswarbo 5y ago> "lambda f:" gives away very little information about what is about to happen. "if f:" gives away some information about what is about to happen. I think that's an unfair comparison: If 'the thing that happens' for "if f:" is 'branch on the truthyness of f', then I agree that's pretty clear. However, if we're going to ignore the content of the branches then we should also ignore the body of the function, so "lambda f:" is also pretty clear: 'parameterise with f'. If we're worried that "lambda f:" could do pretty much anything in the body, then we should also worry that "if f:" can do pretty much anything in the branches.
- ehsankia 5y agoIndeed, there are many such explicit omissions in python (switch statements, assignment expressions (before 3.8), increment/decrement operator, etc) that may seem to some as a bug, but it really is an explicit decision and part of what makes Python the clean and readable language it is.
- geekone 5y agodo python lambda expressions not qualify? https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions https://docs.python.org/3/tutorial/controlflow.html#lambda-e...
- ByteJockey 5y agoLambda expressions in python are limited to a single expression. The poster explicitly calls out wanting more than one line.
- mistaken 5y agoIt's possible to execute statements in a lambda through exec. But it's more of hack than what it worth. print((lambda x: [exec('x = x + 1; result = x'), eval('result')][1])(1))
- vorticalbox 5y agoI don't understand why you wouldn't just define a function if you needed multi lines.
- Chris_Newton 5y agoI don't understand why you wouldn't just define a function if you needed multi lines. For the same reason that you wouldn’t necessarily define a function every time you wanted more than one line in the body of an if statement or for loop. In a functional programming style, typically most of your control structures are represented as higher-order functions and you pass them other functions where you might use nested blocks of statements in an imperative style. That is, where imperative pseudocode might look like this: for n in [0..10]: output_array[n] = n * n some corresponding functional pseudocode might look more like this: output_array = for_each [0..10] (n -> n * n) In some functional languages, it’s even idiomatic to write the supporting function so it reads more like this (borrowing Haskell’s $ notation, which avoids the awkward parentheses): output_array = for_each [0..10] $ \n -> n * n Now you might want a multiline body for the supporting function in much the same situations that you might want a multiline body for the imperative for loop: for n in [0..10]: location = get_location(n) route = fastest_route_to(location) times[n] = average_journey_time(route) times = for_each [0..10] $ \n -> location = get_location(n) route = fastest_route_to(location) average_journey_time(route) Similarly, if the logic you’re using in the inner part of the code is a self-contained concept, you might want to factor it out into a named function of its own in either case. This functional style can be tidy and very flexible in languages that are designed to support it. However, I wouldn’t necessarily encourage it in a language like Python, precisely because Python’s syntax and language features don’t make it natural and concise to write like this.
- mukesh610 5y agoIMO multi-line lambdas are unnecessary; they can't be easily documented or better maintained than a named function. If your anonymous function needs more than a statement it makes perfect sense to define it as a separate named function. Faster to find, document and maintain.
- SketchySeaBeast 5y agoDo you have the same thoughts regarding JavaScript?
- hutrdvnj 5y ago> move its definition outside the point You can define a named function inside a named function and thus limiting its scope. def outer_func(): def inner_func(): print("hi") inner_func()
- ehsankia 5y agoI honestly prefer that, anything function longer than a line probably could use a name that gives it some context, even maybe a short docstring, to make the code more readable.
- chriswarbo 5y agoIt's not so much "lines" that are a problem; it's that lambdas cannot contain any statements. For example, here's a multi-line lambda, containing only expressions: >>> lambda f, pred, xs: [ ... f(x) for ys in xs ... for x in ys ... if pred(x) ... ] <function <lambda> at 0x1113e80d0> Here's a one-line lambda, attempting to use a statement: >>> lambda x: (x += 1) File "<stdin>", line 1 lambda x: (x += 1) ^ SyntaxError: invalid syntax Note that the parentheses are to avoid parsing a '+=' expression with 'lambda x: x' on the left and '1' on the right: >>> lambda x: x += 1 File "<stdin>", line 1 SyntaxError: cannot assign to lambda This restriction is problematic because of the following combination: - Python statements don't compose as well as expressions; we can write one statement followed by another, and we can nest statements (or blocks) inside control statements (if, else, with, etc.), but that's about it. We can't assign statements to variables, we can't call a function on a statement, or return a statement from a function, etc. i.e. we can't abstract over statements (unless we try wrapping them in a named function and using that as an expression, but that can break the underlying functionality of the statement, e.g. 'def ifThenElse(cond, true, false):' will evaluate both branches when called). - Python uses statements for a whole bunch of stuff. In particular it has a 'with foo as bar: baz' statement, rather than e.g. a 'with(foo, lambda bar: baz)' expression; the recent pattern matching functionality is a statement rather than an expresssion; defining a named function is a statement; etc. Taken together, we can often find ourselves needing to introduce a statement somewhere in our code; that requires us to turn a 'lambda' into a 'def'; but 'def' is a statement, so we have to turn any enclosing expression into a statement too; and this propagates up to disintegrate whatever expression we had; leaving us with a big pile of statements, full of boilerplate for managing scopes and names.
- alangpierce 5y agoitertools.groupby isn't really the groupBy operation that people would normally expect. It looks like it would do a SQL-style "group by" where it categorizes elements across the collection, but really it only groups adjacent elements, so you end up with the same group key multiple times, which can cause subtle bugs. From my experience, it's more common for it to be misused than used correctly, so at my work we have a lint rule disallowing it. IMO this surprising behavior is one of the unfriendliest parts of Python when it comes to collection manipulation. https://docs.python.org/3/library/itertools.html#itertools.groupby https://docs.python.org/3/library/itertools.html#itertools.g...
- silvester23 5y agoYes, for itertools.groupby to work as most people would expect, the data needs to be sorted by the grouping key first. That may obviously cause a significant performance hit.
- sfvisser 5y agoIt's common in other languages as well (at least Haskell) and a bit surprising at first. However, a `.sortBy(fn).groupBy(fn)` is easy and of similar efficiency and when you actually need the local-only `groupBy()` you're happy it's there. A bit more expressive overall. At least it is better than lodash' useless groupBy which creates this weird key value mapping, loses order and converts keys to string and what not.
- zmmmmm 5y agoyep, that's a good example of what I refer to as IKEA assembling your groupby. You need to put something like 3 parts together before it does what you want, and they aren't that intuitive (or they only are in retrospect).
- olejorgenb 5y agoThe resulting groups are also iterators which are exhaustible. It's good if you're running group by on a huge dataset to save some memory, but for everyday operations it's another trap to fall into.
- orojackson 5y ago
- sparsely 5y agoI think you've kind of proven the op's point, these all have different patterns and are in different places.
- KingOfCoders 5y agoQ.E.D.
- sleavey 5y agoBy collate, OP might be referring to the behaviour provided by the builtin `zip`.
- dmurray 5y ago> Sibling comment mentioned flatten, which is just [item for sublist for sublist in lst] I never get this one right first time, but surely that's not it.