defmodule Example do
def merge(first_list, second_list)
when is_list(first_list) and is_list(second_list) do
{merged_elements, []} = Enum.map_reduce(first_list, second_list, &do_merge/2)
merged_elements
end
defp do_merge(element, []), do: {element, []}
defp do_merge(element, [head | tail]) do
if element["user_id"] == head["id"] do
merged_element =
head
|> Map.delete("id")
|> Map.merge(element)
{merged_element, tail}
else
{merged_element, tail} = do_merge(element, tail)
{merged_element, [head | tail]}
end
end
end
message_list = [
%{"user_id" => 1, "title" => "test title 1", "body" => "test body"},
%{"user_id" => 5, "title" => "test title 2", "body" => "test body2"},
]
user_list = [
%{"id" => 1, "name" => "name1", "photo" => "image"},
%{"id" => 5, "name" => "name2", "photo" => "image"},
]
IO.inspect Example.merge(message_list, user_list)
Note: My version will only fail if you have at least one more element (by id) in user_list than in message_list, because it’s my extra check. To remove this simply replace [] with _rest_users in &Example.merge/2 function.
This is what I came up with, completing at about the same time you posted this reply:
Still none of the guarantees
Will endlessly loop if a user_id doesn’t match an id.
defmodule Users do
def create_test_data(0, message_acc, user_acc) do
{message_acc, user_acc}
end
def create_test_data(iterations, message_acc, user_acc) do
random_id = :rand.uniform(1000)
test_message = create_test_message(random_id)
test_user = create_test_user(random_id)
create_test_data(iterations - 1, [test_message] ++ message_acc, [test_user] ++ user_acc)
end
def create_test_message(id) do
%{"user_id" => id,
"title" => "test title #{id}",
"body" => "test body #{id}"}
end
def create_test_user(id) do
%{"id" => id,
"name" => "name #{id}",
"photo" => "image #{id}"}
end
def match_messages_to_users([%{"user_id" => id}=message | messages],
[%{"id" => id}=user | users], acc) do
msg = merger(message, user)
match_messages_to_users(messages, users, [msg] ++ acc)
end
def match_messages_to_users([%{"user_id" => _id}=message | messages],
[%{"id" => _}=user | users], acc) do
# flip the user list to match on a new value
match_messages_to_users([message | messages], [users | user], acc)
end
def match_messages_to_users([], [], acc) do
acc
end
def merger(message, user) do
Map.merge(message, user)
|> Map.delete("id")
end
end