Elixir:Stream.drop_while 泛化?
Elixir: Stream.drop_while generalisation?
我想概括这段代码,但看不出如何巧妙地做到这一点:
defmodule Demo do
defp side_effect(bool, label) do
if bool do
IO.puts label
end
end
def go do
{a,b,c} = {4,8,13}
[2,3,4,5,7,8,9,10,11,12] # always in ascending order
|> Stream.drop_while( fn i -> bool = (i<a); side_effect(bool, "a_#{i}"); bool end )
|> Stream.drop_while( fn i -> bool = (i<b); side_effect(bool, "b_#{i}"); bool end )
|> Stream.drop_while( fn i -> bool = (i<c); side_effect(bool, "c_#{i}"); bool end )
|> Enum.to_list
end
end
运行时 (Demo.go) 我得到:
a_2
a_3
b_4
b_5
b_7
c_8
c_9
c_10
c_11
c_12
[]
如我所愿 - 为输入列表中的每个元素执行副作用,最终输出为空列表。
但是是否可以概括这一点,以便我可以以编程方式包括(基于列表)我喜欢的行数:
|> Stream.drop_while( fn i -> bool = (i<x); side_effect(bool, "x_#{i}"); bool end )
如果可以的话,我希望不要探索宏。
流是一种数据结构,这意味着您可以对其进行缩减,在每一步将其细化为一组特定的值:
defmodule Demo do
defp side_effect(var, threshold, label) do
if var < threshold do
IO.puts "#{label}_#{var}"
true
else
false
end
end
def go do
values = [a: 4, b: 8, c: 13]
stream =
Enum.reduce(values, [2,3,4,5,7,8,9,10,11,12], fn {k, v}, acc ->
Stream.drop_while(acc, fn i -> side_effect(i, v, k) end)
end)
Enum.to_list(stream)
end
end
您还可以探索其他解决方案。例如,无需为值的每个部分创建一个流,您可以简单地执行一个过滤操作,检查该值是否小于列表中的阈值。像这样:
defmodule Demo do
defp side_effect(i, values) do
pair = Enum.find(values, fn {_, v} -> i < v end)
case pair do
{k, v} ->
IO.puts "#{k}_#{i}"
false
nil ->
true
end
end
def go do
values = [a: 4, b: 8, c: 13]
[2,3,4,5,7,8,9,10,11,12]
|> Stream.filter(fn i -> side_effect(i, values) end)
|> Enum.to_list()
end
end
我不确定您是否真的需要过滤。如果不是, Stream.map/2 或 Stream.each/2 (专用于副作用)会更好。
我想概括这段代码,但看不出如何巧妙地做到这一点:
defmodule Demo do
defp side_effect(bool, label) do
if bool do
IO.puts label
end
end
def go do
{a,b,c} = {4,8,13}
[2,3,4,5,7,8,9,10,11,12] # always in ascending order
|> Stream.drop_while( fn i -> bool = (i<a); side_effect(bool, "a_#{i}"); bool end )
|> Stream.drop_while( fn i -> bool = (i<b); side_effect(bool, "b_#{i}"); bool end )
|> Stream.drop_while( fn i -> bool = (i<c); side_effect(bool, "c_#{i}"); bool end )
|> Enum.to_list
end
end
运行时 (Demo.go) 我得到:
a_2
a_3
b_4
b_5
b_7
c_8
c_9
c_10
c_11
c_12
[]
如我所愿 - 为输入列表中的每个元素执行副作用,最终输出为空列表。 但是是否可以概括这一点,以便我可以以编程方式包括(基于列表)我喜欢的行数:
|> Stream.drop_while( fn i -> bool = (i<x); side_effect(bool, "x_#{i}"); bool end )
如果可以的话,我希望不要探索宏。
流是一种数据结构,这意味着您可以对其进行缩减,在每一步将其细化为一组特定的值:
defmodule Demo do
defp side_effect(var, threshold, label) do
if var < threshold do
IO.puts "#{label}_#{var}"
true
else
false
end
end
def go do
values = [a: 4, b: 8, c: 13]
stream =
Enum.reduce(values, [2,3,4,5,7,8,9,10,11,12], fn {k, v}, acc ->
Stream.drop_while(acc, fn i -> side_effect(i, v, k) end)
end)
Enum.to_list(stream)
end
end
您还可以探索其他解决方案。例如,无需为值的每个部分创建一个流,您可以简单地执行一个过滤操作,检查该值是否小于列表中的阈值。像这样:
defmodule Demo do
defp side_effect(i, values) do
pair = Enum.find(values, fn {_, v} -> i < v end)
case pair do
{k, v} ->
IO.puts "#{k}_#{i}"
false
nil ->
true
end
end
def go do
values = [a: 4, b: 8, c: 13]
[2,3,4,5,7,8,9,10,11,12]
|> Stream.filter(fn i -> side_effect(i, values) end)
|> Enum.to_list()
end
end
我不确定您是否真的需要过滤。如果不是, Stream.map/2 或 Stream.each/2 (专用于副作用)会更好。