我有一份清單。
[
[4, 5, 6],
[5, 6, 7],
[8, 9, 10],
[20, 21, 22],
[22,23,24]
]
如果 [5,6,7] 的 upper_bound(5) 小于或等于 [4,5,6] 的 lower_bound(6) 則將它們合并在一起,最終串列應如下所示。
[
[
[4, 5, 6],
[5, 6, 7]
],
[8, 9, 10],
[
[20, 21, 22],
[22,23,24]
]
]
我怎樣才能做到這一點?
uj5u.com熱心網友回復:
此答案假定專案始終是順序的,如您的示例所示,并且沒有串列完全包含另一個串列。
首先,使用Ranges會更好,所以我們首先將串列轉換為范圍。
然后我們可以撰寫一個遞回演算法group_ranges/1,用它的前身檢查每個范圍。如果重疊(使用Range.disjoint?/2),請將其添加到組中。如果不重疊,則開始一個新組。
最后,由于您希望不重疊的范圍獨立而不是一組,因此一旦分組完成,我們就會處理這種情況。如果這是嚴格要求,您還可以在此階段將范圍轉換回串列。
defmodule Example do
def run do
[[4, 5, 6], [5, 6, 7], [8, 9, 10], [20, 21, 22], [22, 23, 24]]
|> Enum.map(fn [head | tail] -> head..List.last(tail) end)
|> group_ranges()
|> Enum.map(fn
[single] -> single
group -> group
end)
end
def group_ranges([current | rest]), do: do_group_ranges(rest, [current], [])
defp do_group_ranges([], group, grouped) do
Enum.reverse([Enum.reverse(group) | grouped])
end
defp do_group_ranges([current | rest], [prev | _] = group, grouped) do
if Range.disjoint?(current, prev) do
# Create a new group
do_group_ranges(rest, [current], [Enum.reverse(group) | grouped])
else
# Add to existing group
do_group_ranges(rest, [current | group], grouped)
end
end
end
結果:
iex(1)> Example.run
[[4..6, 5..7], 8..10, [20..22, 22..24]]
uj5u.com熱心網友回復:
假設結果串列的數量少于 32,分組依據Range將起作用。
input
|> Enum.reduce(%{}, fn list, acc ->
{min, max} = Enum.min_max(list)
acc |> Map.keys() |> Enum.reduce_while(nil, fn
mn..mx, _ when min >= mn and min <= mx and max >= mn and max <= mx ->
{:halt, Map.update(acc, mn..mx, & [list | &1])}
mn..mx, _ when min >= mn and min <= mx ->
{:halt, acc |> Map.delete(mn..mx) |> Map.put(mn..max, [list | Map.get(acc, mn..mx)])}
mn..mx, _ when max >= mn and max <= mx ->
{:halt, acc |> Map.delete(mn..mx) |> Map.put(min..mx, [list | Map.get(acc, mn..mx)])}
_, _ -> {:cont, nil}
end) || Map.put(acc, min..max, [list])
end)
|> Map.values()
|> Enum.map(&Enum.reverse/1)
如果串列的預期數量大于 32 并且必須保留排序,則解決方案將更加麻煩。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/424332.html
