Elixir:在元组列表中找到最常见的元素(频率)?

Elixir: Find the most common element (frequency) in a list of tuples?

我知道这是 Whosebug 上的一个常见问题,但找不到专门针对 Elixir 的解决方案。

考虑元组列表:

[
  {1, 3, "1S"},
  {10, 3, "3S"},
  {10, 3, "9S"},
  {10, 3, "10S"},
  {10, 3, "11S"},
  {12, 3, "12S"},
  {13, 3, "13S"}
]

预期结果: 每个元组的第一个参数中最常见的元素是 10。 每个元组的第二个参数中最常见的元素是 3.

是否有执行此操作的函数,或者我必须创建自己的函数来“迭代”每个 elem(list, index) 的元组列表?

不过,这并不那么简单。稍微与下面的行一起工作。

input = [
  {1, 3, "1S"},
  {10, 3, "3S"},
  {10, 3, "9S"},
  {10, 3, "10S"},
  {10, 3, "11S"},
  {12, 3, "12S"},
  {13, 3, "13S"}
]

input
# prepare to transpose a matrix
|> Enum.map(&Tuple.to_list/1)
# transpose
|> fn mx -> List.zip(mx) |> Enum.map(&Tuple.to_list/1) end.()
# group by value, to get to lengths 
|> Enum.map(&Enum.group_by(&1, fn e -> e end))
# get max values
|> Enum.map(&Enum.max_by(&1, fn {_, v} -> length(v) end))
# collect
|> Enum.map(fn {k, v} -> {k, length(v)} end)      

#⇒ [{10, 4}, {3, 7}, {"10S", 1}]

可以组合Enum.frequencies_by/2 and Enum.max_by/2得到出现次数最多的元素:

iex(2)> x |> Enum.frequencies_by(&elem(&1, 0)) |> Enum.max_by(&elem(&1, 1))
{10, 4}
iex(3)> x |> Enum.frequencies_by(&elem(&1, 1)) |> Enum.max_by(&elem(&1, 1))
{3, 7}
iex(4)> x |> Enum.frequencies_by(&elem(&1, 2)) |> Enum.max_by(&elem(&1, 1))
{"10S", 1}

请注意,由于 frequencies_by returns 是一个映射(并且映射是无序的),如果有平局,则 max_by 返回哪个元素是不确定的,您可以见最后一个例子。

其他2个答案都不错。如果您想在事先不知道元组大小的情况下获得所有频率的概览(这永远不会发生),这只是一个替代方案:

input = [
  {1, 3, "1S"},
  {10, 3, "3S"},
  {10, 3, "9S"},
  {10, 3, "10S"},
  {10, 3, "11S"},
  {12, 3, "12S"},
  {13, 3, "13S"}
]

input
|> Enum.map(&Tuple.to_list/1)
|> Enum.reduce(
  %{},
  fn listy, final_map ->
    listy
    |> Enum.with_index()
    |> Enum.reduce(final_map, fn {element, index}, acc ->
      acc
      |> Map.update(index, %{element => 1}, fn existing_value ->
        existing_value |> Map.update(element, 1, fn existing_element -> existing_element + 1 end)
      end)
    end)
  end
)
|> IO.inspect(label: "map with 'tuple element index' as keys and 'map of element frequencies' as values")

Legoscia 的回答告诉您如何计算单个索引的最常见值,但没有说明如何计算元组的所有元素。

这是一个版本,它使用它来计算每个元组索引处最常见的元素 - 它适用于任何长度的元组(假设列表中的所有元组长度相同)。

def most_common_elems([]), do: %{}

def most_common_elems([first | _] = list) do
  max_i = tuple_size(first) - 1
  Map.new(0..max_i, &most_common_at(list, &1))
end

def most_common_at(list, i) do
  max_val =
    list
    |> Enum.frequencies_by(&elem(&1, i))
    |> Enum.max_by(&elem(&1, 1))
    |> elem(0)

  {i, max_val}
end

示例输出:

%{0 => 10, 1 => 3, 2 => "10S"}