Compare two list with map

Viewed 108

I have 2 list with map

products= [
  %{
    "id" => "7",
    "use_count" => 1,
    "name" => "A",
    "price" => "$1",
    "base_count" => 2
  },
  %{
    "id" => "8",
    "use_count" => 0,
    "name" => "B",
    "price" => "$14",
    "base_count" => 0
  },
  %{
    "id" => "9",
    "use_count" => 1,
    "name" => "C",
    "price" => "$29",
    "base_count" => 0
  }
]

and

margin=[
  %{name: "aa", id: 9, base_count: 1},
  %{name: "bb", id: 7, base_count: 1}
]

I want to compare 2 list based on id. If for any base_count in products is less than base_count of margin , then I want throw the error as

        {:error, "product count cant be less than margin count"}

Can anyone please help?

Thanks in advance.

3 Answers

The problem is extremely ill-formed, in products ids are strings, in margins they are integers, what does mean “throw an error” is unclear.

As it is stated, the problem might be approached this way:

lookup = fn id ->
  (Enum.find(margin, &match?(%{id: ^id}, &1)) || %{base_count: 0}).base_count
end

result =
  Enum.reduce(products, %{}, fn %{"id" => id, "base_count" => base_count}, acc ->
    id = String.to_integer(id)
    diff = lookup.(id) - base_count
    if diff > 0,
      do: Map.put(acc, id, diff),
      else: acc
  end)

Now one might check if result is not empty and “throw” the error, whatever it means.


Sidenote: I would start with normalizing ids and maybe grouping margins by id to make lookups more efficient, but this I would leave for the homework.

A typical problem that can be solved by hashtable (or map (the datatype) in Elixir).

  1. Index your products by id
products_by_id = products
                 |> Stream.map(fn product -> {String.to_integer(product["id"]), product} end)
                 |> Enum.into(%{})
  1. Check if there's a margin whose base_count is greater than the corresponding product's base_count.
if Enum.any?(margin, fn m -> m[:base_count] > products_by_id[m[:id]]["base_count"] end) do
  {:error, "product count cant be less than margin count"}
end

As Aleksei Matiushkin said, consistency of data types is very important. It helps you write less code and avoid many bugs. So you really should fix your data first if you can.

Consider products and margins ids are the same type

margin_base_count = Enum.into(margin, %{}, &{&1.id, &1.base_count})

Enum.reduce_while(products, :ok, fn %{"id" => id, "base_count" => base_count}, _acc ->
  case base_count < margin_base_count[id]  do
    true -> {:halt, {:error, "product count cant be less than margin count"}}
    false -> {:cont, :ok}
  end
end)

Related