Yes, as this was not mentioned originally.
No worries.
No, it’s not. As above you have added a special cases not mentioned before. Here is the current error:
** (FunctionClauseError) no function clause matching in Example.merge/3
The following arguments were given to Example.merge/3:
# 1
[]
# 2
[{"666", "testName666"}]
# 3
false
We can see that we have done with data
, but still have extra names
list elements. This means that we only need to modify a strict condition that finishes our recursive process i.e.
# in case no extra names we can strictly pattern match here
defp merge([], [], _last_matched), do: []
# in case we do not care about more items in `names` list
defp merge([], _names, _last_matched), do: []
Also I have simplified my example a bit:
defmodule Example do
def sample(data, names) when is_list(data) and is_list(names) do
# a list of names
# reduce it with an empty list
names
|> Enum.reduce([], fn %{mediaTailoId: ids_map, name: name}, acc ->
# take a map value under mapData key
ids_map
# change atom id to string
|> Enum.map(fn {id, _value} -> {Atom.to_string(id), name} end)
# concat the result with acc
|> then(&(acc ++ &1))
end)
# the original names are sorted partially i.e. only in specified mediaTailoId
# to fix that we simply need to sort the flat list result by id
|> Enum.sort_by(&elem(&1, 0))
|> then(&merge(data, &1))
end
# function head is required when using a default argument(s)
# in functions with multiple clasule
defp merge(data, names, last_matched \\ false)
# when done simply finish a recursive call returning an empty list as result tail
defp merge([], _names, _last_matched), do: []
# if id matches add a new map to result and continue with same data and the rest of names
defp merge([%{channelId: id} = map | _data_tail] = data, [{id, name} | names], _last_matched) do
[Map.merge(map, %{name: name}) | merge(data, names, true)]
end
# if id does not match and previous clause matched for this id
# we simply continue with rest of data and same names
defp merge([_data_head | data], names, true), do: merge(data, names, false)
# otherwise if id still does not match and previous clause do not matched for this id even once
# add a new map with an empty name and continue with rest of data and same names
# the combination of last_matched boolean argument and this clause
# is required in case we do not have any names for specific data like it is for "444" id
defp merge([map | data], names, false) do
[Map.merge(map, %{name: ""}) | merge(data, names, false)]
end
end
data1 = [
%{
channelId: "1",
# fix: describtion -> description
description: "dev-test_001",
tags: %{pipelineId: "1001", pipelineTemplate: "live-drm"}
},
%{
channelId: "2",
# fix: describtion -> description
description: "dev-test_002",
tags: %{pipelineId: "1002", pipelineTemplate: "live-drm"}
},
%{
channelId: "3",
# fix: describtion -> description
description: "dev-test_003",
tags: %{pipelineId: "1003", pipelineTemplate: "live-drm"}
},
%{
channelId: "4",
# fix: describtion -> description
description: "dev-test_004",
tags: %{pipelineId: "1004", pipelineTemplate: "live-drm"}
}
]
data2 = [
%{
mediaTailoId: %{"1": "channel1_data", "2": "channel2_dadta", "3": "channel3_dadta"},
mediaTailorRegion: "us-east-1",
name: "testName1"
},
%{
mediaTailoId: %{"1": "channel1_data", "2": "channel2_dadta"},
mediaTailorRegion: "us-east-2",
name: "testName2"
},
%{mediaTailoId: %{"1": "channel1_data"}, mediaTailorRegion: "us-east-3", name: "testName3"},
%{mediaTailoId: %{"666": "channel1_data"}, mediaTailorRegion: "us-east-3", name: "testName666"}
]
expect_data = [
%{
channelId: "1",
description: "dev-test_001",
tags: %{pipelineId: "1001", pipelineTemplate: "live-drm"},
name: "testName1"
},
%{
channelId: "1",
description: "dev-test_001",
tags: %{pipelineId: "1001", pipelineTemplate: "live-drm"},
name: "testName2"
},
%{
channelId: "1",
description: "dev-test_001",
tags: %{pipelineId: "1001", pipelineTemplate: "live-drm"},
name: "testName3"
},
%{
channelId: "2",
description: "dev-test_002",
tags: %{pipelineId: "1002", pipelineTemplate: "live-drm"},
name: "testName1"
},
%{
channelId: "2",
description: "dev-test_002",
tags: %{pipelineId: "1002", pipelineTemplate: "live-drm"},
name: "testName2"
},
%{
channelId: "3",
description: "dev-test_003",
tags: %{pipelineId: "1003", pipelineTemplate: "live-drm"},
# fix: "testName2" -> "testName1"
name: "testName1"
},
%{
channelId: "4",
description: "dev-test_004",
tags: %{pipelineId: "1004", pipelineTemplate: "live-drm"},
name: ""
}
]
iex> Example.sample(data1, data2) == expect_data
true