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"}
我知道这是 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"}