Custom Elixir Module for Filtering Lists

Create a custom Elixir module to filter items in a list, demonstrated through a warehouse order system example.

I wanted to create a module with the ability to reject one item in a list, and return the new list. We have an orders list that contains fruits and vegetables that need to be shipped out to customers. This orders list is what someone could use in the warehouse to pick up the items.

orders = [
%{
  item_id: 1,
  item_name: "Apple",
  item_weight: 1,
  customer_id: 1,
  delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
},
%{
  item_id: 1,
  item_name: "Apple",
  item_weight: 1,
  customer_id: 1,
  delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
},
%{
  item_id: 1,
  item_name: "Apple",
  item_weight: 1,
  customer_id: 3,
  delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
},
%{
  item_id: 2,
  item_name: "Orange",
  item_weight: 1,
  customer_id: 1,
  delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
},
%{
  item_id: 2,
  item_name: "Orange",
  item_weight: 1,
  customer_id: 3,
  delivery_uuid: "f50d1032-a40a-4ed9-bf49-9917e89a1ce6"
},
%{
  item_id: 2,
  item_name: "Carrot",
  item_weight: 1,
  customer_id: 3,
  delivery_uuid: "f50d1032-a40a-4ed9-bf49-9917e89a1ce6"
}
]

Reject one

In this example we need to remove 1 order of a specific customer_id, item_id and delivery_uuid. Make it a module so that it can be used in other areas of the application.

defmodule Filter do
  def reject_one([], _fun), do: []

  def reject_one([head | tail], fun) do
    if fun.(head), do: tail, else: reject_one(tail, fun, [head])
  end

  def reject_one([head | tail], fun, acc) do
    if fun.(head), do: acc ++ tail, else: reject_one(tail, fun, [head | acc])
  end
end

Then within your application you could write something out like this.

Filter.reject_one(orders, fn x ->
  x[:customer_id] == 1 and
  x[:delivery_uuid] == "729ae97a-d75b-4027-aec2-14da53c4744f" and
  x[:item_id] == 1
end)

You passed in a function that looks for a specific customer_id, deliver_uuid and item_id. The result is a returned list with the rejected item removed from the list.

In this example the customer_id: 1 had 2 orders of an apple at a specific delivery_uuid and now have 1 order of apple.

[
  %{
    item_id: 1,
    item_name: "Apple",
    item_weight: 1,
    customer_id: 1,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
  },
  %{
    item_id: 1,
    item_name: "Apple",
    item_weight: 1,
    customer_id: 1,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
  },
  %{
    item_id: 1,
    item_name: "Apple",
    item_weight: 1,
    customer_id: 3,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
  },
  %{
    item_id: 2,
    item_name: "Orange",
    item_weight: 1,
    customer_id: 1,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
  },
  %{
    item_id: 2,
    item_name: "Orange",
    item_weight: 1,
    customer_id: 3,
    delivery_uuid: "f50d1032-a40a-4ed9-bf49-9917e89a1ce6"
  },
  %{
    item_id: 2,
    item_name: "Carrot",
    item_weight: 1,
    customer_id: 3,
    delivery_uuid: "f50d1032-a40a-4ed9-bf49-9917e89a1ce6"
  }
]

Improving the module

The example above is basic and for illustrative purposes. In this example below we are going to include that Filter module as part of another module called MasterList.

As the name implies, MasterList will be responsible for managing the master list of orders.

With this module function MasterList.remove_order_item/2 we can pass in the order_item and orders and get our new orders list.

defmodule MasterList do
  alias Filter

  def remove_order_item(orders, order_item) do
    Filter.reject_one(orders, fn x ->
      x[:customer_id] == order_item[:customer_id] and
      x[:delivery_uuid] == order_item[:delivery_uuid] and
      x[:item_id] == order_item[:item_id]
      end)
  end
end

The new result

iex> order_item = %{
  item_id: 1,
  item_name: "Apple",
  item_weight: 1,
  customer_id: 1,
  delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f"
}

iex> MasterList.remove_order_item(orders, order_item)

[
  %{
    customer_id: 1,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f",
    item_id: 1,
    item_name: "Apple",
    item_weight: 1
  },
  %{
    customer_id: 3,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f",
    item_id: 1,
    item_name: "Apple",
    item_weight: 1
  },
  %{
    customer_id: 1,
    delivery_uuid: "729ae97a-d75b-4027-aec2-14da53c4744f",
    item_id: 2,
    item_name: "Orange",
    item_weight: 1
  },
  %{
    customer_id: 3,
    delivery_uuid: "f50d1032-a40a-4ed9-bf49-9917e89a1ce6",
    item_id: 2,
    item_name: "Orange",
    item_weight: 1
  },
  %{
    customer_id: 3,
    delivery_uuid: "f50d1032-a40a-4ed9-bf49-9917e89a1ce6",
    item_id: 2,
    item_name: "Carrot",
    item_weight: 1
  }
]