Junaid Farooq
Junaid Farooq

Reputation: 2608

update a List with structs Elixir

I have an an object as

%{
  shares: []
}

I want to add a struct %Cs{name: "Junaid1"}, %Cs{name: "Junaid2"} into the list through Enum.each or map, is that possible to do?

Okay for just more brief I am updating question again..

 Enum.each(email_array, fn (email) ->
    with {:found_user, sharee} <- ensure_user(email)
    do
      case CameraShare.create_share(camera, sharee, caller, params["rights"], params["message"]) do
        {:ok, camera_share} ->
           #Add camera_share to list
        {:error, changeset} ->
          #Add error to a list
      end
    else
      {:not_found, email} ->
        case CameraShareRequest.create_share_request(camera, email, caller, params["rights"], params["message"]) do
          {:ok, camera_share_request} ->
            #Add camera_share to list
          {:error, changeset} ->
            #Add error to list
        end
    end
  end)

and then at the end of Enum.each.. there will be a map as

%{
   shares: [all shares],
   errors: [all errors]
}

where as each share is of type %CameraShare{__meta__: #Ecto.Schema.Metadata<:loaded, "camera_shares">}

Upvotes: 1

Views: 2790

Answers (2)

Sheharyar
Sheharyar

Reputation: 75820

You can create a simple method like this:

def add_share(%{shares: shares} = map, share) do
  %{ map | shares: [share | shares] }
end

And call it to add items to the lists in the map:

%{shares: []}
|> add_share(%Cs{name: "Junaid1"})
|> add_share(%Cs{name: "Junaid2"})

Result:

%{shares: [%Cs{name: "Junaid2"}, %Cs{name: "Junaid1"}]}

Upvotes: 0

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

map = %{
  shares: [%{name: "Junaid0"}]
}
add_shares = [%{name: "Junaid1"}, %{name: "Junaid2"}]

Straigt list concatenation

%{map | shares: map[:shares] ++ add_shares}

Comprehension

%{map | shares: (for share <- add_shares, into: map[:shares], do: share)}

Enum.reduce

Enum.reduce(add_shares, map, fn share, acc ->
  %{acc | shares: [share | acc[:shares]]}
end)

Enum.into

%{map | shares: Enum.into(add_shares, map[:shares], & &1)}

FWIW:

Adding an element to already existing list:

list = []
element = 42

list1 = [element | list]
#⇒ [42]
list2 = [element | list1]
#⇒ [42, 42]

Answer to updated question (simplified):

Enum.reduce(email_array, {[], []}, fn
  email, {shares, changes} = _acc ->
    with {:found_user, sharee} <- ensure_user(email) do
      case :camera_share do
        {:ok, camera_share} ->
           {[camera_share | shares], changes}
        {:error, changeset} ->
           {shares, [changeset | changes]}
      end
    else
      # basically the same
      # make sure ALL branches return an acumulator
    end
  end)

The above would return a tuple {shares, changes} that you might assign to anything.

Upvotes: 2

Related Questions