pertsevds
Different behavior between List.flatten() and Enum/Stream.flat_map()
When i use List.flatten() it would flatten a deep list with every nested .
iex> list = [[],["ant",["hello","hi",[[[]]]], "bat"], ["cat", "dog"]]
[[], ["ant", ["hello", "hi", [[[]]]], "bat"], ["cat", "dog"]]
iex> List.flatten(list)
["ant", "hello", "hi", "bat", "cat", "dog"]
As expected.
But when i do Stream.flat_map()
iex(6)> list = [[],["ant",["hello","hi",[[[]]]], "bat"], ["cat", "dog"]]
[[], ["ant", ["hello", "hi", [[[]]]], "bat"], ["cat", "dog"]]
iex(7)> list
[[], ["ant", ["hello", "hi", [[[]]]], "bat"], ["cat", "dog"]]
iex(8)> |> Stream.flat_map(& &1)
#Function<60.124013645/2 in Stream.transform/3>
iex(9)> |> Enum.to_list()
["ant", ["hello", "hi", [[[]]]], "bat", "cat", "dog"]
It flattens only the first level of the list. It’s a flatten() with depth == 1.
And that was not what i expected.
I needed a deep_flatten() for Stream, so i’ve made it like this:
defmodule ExTelnet.StreamDeepFlatten do
def deep_flatten(enumerables) do
deep_flat_map(enumerables, & &1)
end
def deep_flatten(first, second) do
deep_flat_map([first, second], & &1)
end
def deep_flat_map(enum, mapper) when is_function(mapper, 1) do
Stream.transform(enum, nil, fn val, nil ->
case val do
val when is_list(val) -> {deep_flat_map(val, mapper), nil}
val -> {[mapper.(val)], nil}
end
end)
end
end
Works as expected for me:
iex(2)> list = [[],["ant",["hello","hi",[[[]]]], "bat"], ["cat", "dog"]]
iex(3)> list
iex(4)> |> Stream.map(&IO.inspect(&1))
iex(5)> |> ExTelnet.StreamDeepFlatten.deep_flatten()
iex(6)> |> Stream.map(&IO.inspect(&1))
iex(7)> |> Stream.map(&("seen " <> &1))
iex(8)> |> Stream.map(&IO.inspect(&1))
iex(9)> |> Enum.to_list()
[]
["ant", ["hello", "hi", [[[]]]], "bat"]
"ant"
"seen ant"
"hello"
"seen hello"
"hi"
"seen hi"
"bat"
"seen bat"
["cat", "dog"]
"cat"
"seen cat"
"dog"
"seen dog"
["seen ant", "seen hello", "seen hi", "seen bat", "seen cat", "seen dog"]
So what i’m questioning myself now is: “Am I reinvening the wheel? Maybe there is some better simpler method and I just don’t see it?”
Most Liked
josevalim
Hi everyone, I believe @davaeron understands the differences between them. The question is about naming.
Correct. This is common nomenclature in all functional languages. Also add Scala and Erlang to your list.
You should read it as a “flat map operation”, i.e. as a map operation that joins its consecutive results, not as a “map plus flatten”.
Sebb
lucaong
One reason: flat_map flattening a single level, and flatten flattening multiple levels, produces a more versatile behavior: if one needs to flatten only a single level (maybe the nested items are collections themselves and should be treated as individual items) one can use flat_map. If multiple levels should be flattened, one can call flatten inside the function called by flat_map.
Last Post!
pertsevds
Popular in Discussions
Other popular topics
Chat & Discussions>Discussions
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #hex
- #security









