5 ms·
Of course in Elixir[1] reduce is more efficient (at least memory-wise) than map/flat_map, but in case of scripting it usually doesn't matter (unless this JSON f
by nivertech 3y ago
Of course in Elixir[1] reduce is more efficient (at least memory-wise) than map/flat_map, but in case of scripting it usually doesn't matter (unless this JSON file is huge, but it's fully loaded into memory and parsed there anyway).
I would rewrite the example from the post like this (NOTE: I didn't run it, so it might be slightly incorrect):
#/usr/bin/env elixir
"file.json"
|> File.read!()
|> Jason.decode!()
|> Enum.flat_map(& &1["children"])
|> Enum.map(&{&1["id"], &1})
|> Enum.into(%{})
---
1. although map is much easier to parallelize/vectorize (e.g. in Array PLs)
- rkangel 3y agoIt's slightly more verbose but I have mostly stopped using the & notation to produce functions out of thin air[1]. I find the following code is much more easily readable - more welcoming to the less experienced, less brain load for the more experienced: #/usr/bin/env elixir "file.json" |> File.read!() |> Jason.decode!() |> Enum.flat_map(fn x -> x["children"] end) |> Enum.map(fn x -> {x["id"], x} end) |> Enum.into(%{}) [1] The `&a_function_with_odd_arguments(&2, &1)` type notation can still be very useful and is (subjectively) a bit less symbol-salad.
- nivertech 3y agoI dislike Elixir's abuse of sigils (it's inhereted from Perl via Ruby). The capture operator syntax in Elixir isn't a very ergonomic design. It uses the same symbol for both fun and arguments, and also for MFAs (&M.f/a). It doesn't allow nesting, so in these cases there is no choice but to use the full notation. In case the intent isn't clear from the code, I'll also use the full notation. Also, I think it's much more acceptable to use shorthand/sugar in one-off scripts rather than in "real" code. NOTE: in your example you use "x" for argument, so it's not much better than "&1". Since you already using the full notation, it's better to meaningfull argument names, such as "item" and "subitem".
- Lutger 3y agoFor readers not used to Elixirs operators - which I am - "x" is much easier to understand than "&1" for two reasons. First, because the syntax of the full notation resembles how anonymous functions are done in almost every mainstream language that has them. Second, the character "x" is very often used as a name for the first parameter of an anonymous function, which reinforces the first point. If I see only only this: (x,y) -> ... I can guess quite well what x and y are used for, and I suspect I am not the only developer who recognizes this as a 'parameter list' partly because the names happen to use 'x' and 'y' which are otherwise non-descriptive. Nevertheless, your point still stands.
- nivertech 3y agoIf you alrady decided to use a full form, then the difference between fn x -> ... x ... end and fn item -> ... item ... end is not that far, but it makes a huge different for other team members and even for the future self. Beside Elixir/Erlang, I also a kdb+/q (an APL family language) developer, and there the 1st,2nd,3rd arguments of the function are called x, y, z correspondingly by default. E.g. instead of f: {[n] n*n} f 5 => 25 you can write: f: {x*x} f 5 => 25 or instead of: add: {[a;b] a+b} add[10;20] => 30 you can write: add: {x+y} add[10;20] => 30 There is a wide range of syntactic sugar and shorthands in PLs. If your PL supports multiple options, you need to choose the best one depending on the context or situation. Having said that, I believe that modern PLs plagued with the flexibility syndrome, and I would prefer it if the PL designers selected a single approach and sticked to it.
- sodapopcan 3y agoI never buy the "for those not used to the language" argument. People are going to learn the language and then it won't be a mystery anymore. `x` is only clearer than `&1` if you don't want to get used to the syntax, but once you're used to it it becomes second nature and is much more concise in certain situations. I mostly only use it for things like `Enum.map(users, & &1.name)`. Basically I never use &2 (well, I probably have once of twice before, lol).
- _randyr 3y agoYou can skip the last Enum.map/into and just use Map.new: "file.json" |> File.read!() |> Jason.decode!() |> Stream.flat_map(& &1["children"]) |> Map.new(fn child -> {child["id"], child} end)