newbie1

newbie1

How to get min values structs from array?

Hi, I have an array of structs:

array = [%{count: 1, img: 1}, %{count: 1, img: 2}, %{count: 3, img: 3},
 %{count: 1, img: 4}]```

What i want is return the struct with minimum value. if there is more than 1 struct which contains minimum value like “1” it should return all of them. in this case it should return:

array = [%{count: 1, img: 1}, %{count: 1, img: 2}, %{count: 1, img: 4}]

The check is on “count”

Thanks in advance

Most Liked

peerreynders

peerreynders

A list of maps actually …

There is a Enum.min_by/3 but that returns only a single value. But all these functions are linked to the source so you can find out how that works - it turns out that it is based on - Lists.foldl/3 - a function you can use to solve your problem (or Enum.reduce/3).

Now both reduce and foldl work on an accumulator value - my choice would be a tuple like (min_value, [maps_with_min_value]). So every time a new element of the list is inspected a decision has to be made:

  • Is this lower than min_value? If yes, start a new list for the new min value resulting in a tuple (new_min_value, [map_with_new_min_value])
  • Is this equal to min_value? If yes, add the new map to the list, i.e. (min_value,[new_map| others])
  • Otherwise leave the tuple unchanged.

Note also that you should also account for being handed an empty list - i.e. there is no minimum - then the resulting list should simply be empty. But if there are any maps to process in the list you simply take the first map as your initial minimum for the accumulator and process the remainder of the list with foldl or reduce.

PS: With pattern matching you can just use the list as an accumulator (i.e. peek inside the first element of the list rather than holding min_value separately).

OvermindDL1

OvermindDL1

If you want it to output in exactly the same output as you stated (so the same order as the original) then I’d just do this:

╰─➤  iex
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.6.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> array = [%{count: 1, img: 1}, %{count: 1, img: 2}, %{count: 3, img: 3}, %{count: 1, img: 4}]
[
  %{count: 1, img: 1},
  %{count: 1, img: 2},
  %{count: 3, img: 3},
  %{count: 1, img: 4}
]
iex(2)> {_, array} = Enum.reduce(Enum.reverse(array), {nil, []}, fn
...(2)>   %{count: count} = v, {c, a} when count < c -> {count, [v]}
...(2)>   %{count: count} = v, {count, a} -> {count, [v | a]}
...(2)>   _, acc -> acc
...(2)> end)
{1, [%{count: 1, img: 1}, %{count: 1, img: 2}, %{count: 1, img: 4}]}

peerreynders

peerreynders

It’s worth noting that this approach relies on term ordering:

number < atom < reference < function < port < pid < tuple < map < list < bitstring

i.e. because nil is actually :nil (i.e. an atom)

number < nil

is always true

jfeng

jfeng

Another option for your entertainment:

def min_values([head | tail]) do
  acc_min = fn(x, [a | _] = acc) ->
    cond do
      x.count == a.count -> [x | acc]
      x.count > a.count -> acc
      x.count < a.count -> [x]
    end
  end

  List.foldl(tail, [head], acc_min) |> Enum.reverse()
end

edit Hah, teaches me to skim too quickly, looks like thats pretty much exactly what peerreynders described but without dealing with empty lists. Here’s a better recursive version:

def min_values(list, acc \\ [])
def min_values([head | tail], []), do: min_values(tail, [head])
def min_values([head | tail], [%{count: val} | _] = acc) do
  cond do
    head.count == val -> min_values(tail, [head | acc])
    head.count > val -> min_values(tail, acc)
    head.count < val -> min_values(tail, [head])
  end
end
def min_values([], acc), do: Enum.reverse(acc)

Where Next?

Popular in Questions Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Exadra37
Sometimes I want to check if the input into a function is not a blank string. My first approach: defmodule Example do def do_stuff(s...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement