List 如何在不比较完整列表的情况下检测列表更改
我有一个函数,如果自生成此术语/列表以来,它正在使用的术语/列表有任何更改,则该函数将失败。我希望避免检查每个参数是否仍然相同。因此,每次生成术语/列表以执行CRC或类似操作时,我都会考虑。在使用它之前,我会再次生成CRC,这样我可以99999%确定术语/列表仍然相同 关于一个特殊的答案,我正在用Erlang编程,我正在考虑使用以下类型的函数:List 如何在不比较完整列表的情况下检测列表更改,list,erlang,List,Erlang,我有一个函数,如果自生成此术语/列表以来,它正在使用的术语/列表有任何更改,则该函数将失败。我希望避免检查每个参数是否仍然相同。因此,每次生成术语/列表以执行CRC或类似操作时,我都会考虑。在使用它之前,我会再次生成CRC,这样我可以99999%确定术语/列表仍然相同 关于一个特殊的答案,我正在用Erlang编程,我正在考虑使用以下类型的函数: -spec(list_crc32(List :: [term()]) -> CRC32 :: integer()). 我使用这个术语,因为它是一
-spec(list_crc32(List :: [term()]) -> CRC32 :: integer()).
我使用这个术语,因为它是一个术语列表(erlang已经有一个默认的快速CRC库,但用于二进制值)。我已经考虑使用<代码>“Erlang:CRC32(TyMytoTo-二进制(术语))”< /C> >,但不确定是否有更好的方法。
你觉得怎么样?
尊敬的Borja。如果没有更多的上下文,就有点难以理解为什么会出现这个问题,特别是因为Erlang术语是不可变的——一旦赋值,任何其他操作都不能更改变量的值,即使在同一个函数中也是如此 <> >如果你的问题是“我如何快速断言<代码>真的= a==a < /代码>?”然后考虑这个代码:
A = generate_list()
% other things in this function happen
A = A.
上面的代码片段总是断言A
仍然是A
,因为不可能像在Python中那样更改A
如果您的问题是“如何断言一个新列表的值生成的值与另一个已知列表的值完全相同?”则使用匹配或实际断言是最快的方法:
start() ->
A = generate_list(),
assert_loop(A).
assert_loop(A) ->
ok = do_stuff(),
A = generate_list(),
assert_loop(A).
上面的assert\u loop/1
函数强制断言generate\u list/0
的输出仍然是A。不知道系统中可能发生的其他事情会影响该函数的结果,但行A=generate\u list()如果返回的列表与A
的值不完全相同,则将崩溃
事实上,在本例中,无论执行多少次上述assert\u loop/1
,都无法更改A
现在考虑一种不同的风格:
compare_loop(A) ->
ok = do_stuff(),
case A =:= generate_list() of
true -> compare_loop(A);
false -> terminate_gracefully()
end.
在这里,我们为自己提供了除崩溃之外的其他选择,但效果最终是相同的,因为=:=
不仅仅是一个相等的测试,它是一个匹配测试,意味着这两个值的计算结果不相同,而是它们实际匹配
考虑:
1> 1 == 1.0.
true
2> 1 =:= 1.0.
false
比较两个术语的最快方法部分取决于所涉及列表的大小,特别是取决于您是否期望断言更频繁地通过或失败
如果检查更容易失败,那么最快的检查是使用带有=
的断言、带有==
的等价性测试或带有=:=
的匹配测试,而不是使用erlang:phash2/1
。为什么?因为一旦遇到不匹配的元素,这些测试就会返回false——如果不匹配发生在列表的开头附近,那么完全可以避免对两个列表进行完全遍历
如果希望更频繁地通过检查,则类似于erlang:phash2/1
的速度会更快,但前提是列表很长,因为每次迭代只会完全遍历一个列表(原始列表的哈希已经存储)。不过,在短列表中,简单的比较可能仍然比计算散列、存储散列、计算另一个散列然后比较散列(显然)要快。所以,和往常一样,基准
phash2版本可能如下所示:
start() ->
A = generate_list(),
Hash = erlang:phash2(A),
assert_loop(Hash).
assert_loop(Hash) ->
ok = do_stuff(),
Hash = erlang:phash2(generate_list()),
loop(Hash).
同样,这是一个断言循环,它将崩溃而不是干净地退出,因此需要根据您的需要进行调整
不过,基本的谜团仍然存在:在一种具有不可变变量的语言中,为什么您不知道某些东西是否会发生变化?这几乎可以肯定是程序中其他地方潜在体系结构问题的一个症状——要么就是对Erlang中不变性的误解。如果没有更多的上下文,就有点难以理解为什么会出现这个问题,特别是因为Erlang术语是不可变的——一旦赋值,任何其他操作都不能更改变量的值,即使在同一个函数中也是如此
<> >如果你的问题是“我如何快速断言<代码>真的= a==a < /代码>?”然后考虑这个代码:
A = generate_list()
% other things in this function happen
A = A.
上面的代码片段总是断言A
仍然是A
,因为不可能像在Python中那样更改A
如果您的问题是“如何断言一个新列表的值生成的值与另一个已知列表的值完全相同?”则使用匹配或实际断言是最快的方法:
start() ->
A = generate_list(),
assert_loop(A).
assert_loop(A) ->
ok = do_stuff(),
A = generate_list(),
assert_loop(A).
上面的assert\u loop/1
函数强制断言generate\u list/0
的输出仍然是A。不知道系统中可能发生的其他事情会影响该函数的结果,但行A=generate\u list()如果返回的列表与A
的值不完全相同,则将崩溃
事实上,在本例中,无论执行多少次上述assert\u loop/1
,都无法更改A
现在考虑一种不同的风格:
compare_loop(A) ->
ok = do_stuff(),
case A =:= generate_list() of
true -> compare_loop(A);
false -> terminate_gracefully()
end.
在这里,我们为自己提供了除崩溃之外的其他选择,但效果最终是相同的,因为=:=
不仅仅是一个相等的测试,它是一个匹配测试,意味着这两个值的计算结果不相同,而是它们实际匹配
考虑:
1> 1 == 1.0.
true
2> 1 =:= 1.0.
false
比较两个术语的最快方法部分取决于所涉及列表的大小,特别是取决于您是否期望断言更频繁地通过或失败
如果预计检查失败的频率更高,那么最快的检查是使用断言