How to Enum.map to get single list in multi-layer maps?

Hi, everyone

i have struct like this

data =
[
	%{ id: 0, list: [ %{ cid: 0 }, %{ cid: 1 }, %{ cid: 2 } ] },
	%{ id: 1, list: [ %{ cid: 3 }, %{ cid: 4 }, %{ cid: 5 } ] },
]

#And i try to get inner list and merge to single one 		
list = data |> Enum.map( fn( d )-> d.list end )
Logger.info( "[list] #{inspect list}" )

#but i get this
[list] [ [%{cid: 0}, %{cid: 1}, %{cid: 2}], [%{cid: 3}, %{cid: 4}, %{cid: 5}] ]

has simple way can get like this?

[list] [ %{cid: 0}, %{cid: 1}, %{cid: 2}], [%{cid: 3}, %{cid: 4}, %{cid: 5}]]

thanks for help :blush:

okay… i got it

test "Merge multiple list from List map child" do
		
	data =
	[
		%{ id: 0, list: [ %{ cid: 0 }, %{ cid: 1 }, %{ cid: 2 } ] },
		%{ id: 1, list: [ %{ cid: 3 }, %{ cid: 4 }, %{ cid: 5 } ] },
	]
		
	list = data |> Enum.map( fn( d )-> d.list end ) |> Enum.reduce( [], fn( items, list ) -> list ++ items end )
		
	assert( length( list ) == 6 )
end

You can make it a single pass with:

list = data |> Enum.reduce([], fn(%{list: l}, acc) -> l ++ acc end)

2 Likes

oh, that’s good thank you :smiley:

Just a small change…

list = data |> Enum.reduce([], fn(%{list: l}, acc) -> [l | acc] end)

I think using the second form is slightly better in terms of performance :slight_smile:

I thought about that too, but when trying it out in iex,

iex(21)> t = Enum.reduce(data, [], fn(%{list: l}, acc) -> [ l | acc ] end)  
[[%{cid: 3}, %{cid: 4}, %{cid: 5}], [%{cid: 0}, %{cid: 1}, %{cid: 2}]]
iex(22)> t = Enum.reduce(data, [], fn(%{list: l}, acc) -> l ++ acc end)   
[%{cid: 3}, %{cid: 4}, %{cid: 5}, %{cid: 0}, %{cid: 1}, %{cid: 2}]

I imagine it’s because l is not a single element?

1 Like

yes, I think this too :slight_smile: I forgot I need to flatten after… because l is a list

Enum.flat_map(data, & &1.list)
5 Likes

that’s is best! thanks !!:heart_eyes: