如何在不比较完整列表

时间:2017-10-24 19:48:03

标签: list erlang

我有一个函数,如果自生成这个术语/列表以来它所使用的术语/列表有任何变化,它将失败。我想避免检查每个参数是否仍然相同。所以每次我生成术语/列表来执行CRC或类似的东西时我都会想到。在使用它之前,我会再次生成CRC,所以我可以99,9999%确定术语/列表仍然相同。

转到一个特定的答案,我在Erlang编程,我正在考虑使用以下类型的函数:

-spec(list_crc32(List :: [term()]) -> CRC32 :: integer()).

我使用term,因为它是一个术语列表,(erlang已经有一个默认的快速CRC库,但是对于二进制值)。我考虑使用"erlang:crc32(term_to_binary(Term))",但不确定是否有更好的方法。

你怎么看? 此致,Borja。

1 个答案:

答案 0 :(得分:2)

如果没有更多的上下文,有点难以理解为什么你会遇到这个问题,特别是因为Erlang术语是不可变的 - 一旦分配了没有其他操作就可以改变变量的值,而不是即使是在同一个功能中。

因此,如果您的问题是"如何快速断言true = A == A?"然后考虑这段代码:

A = generate_list()
% other things in this function happen
A = A.

上面的代码段总是断言A仍然是A,因为无法改变A ,就像你可能做的那样比方说,Python。

如果您的问题是"我如何声明列表的值完全与不同的已知列表相同?&#34 ;然后使用匹配或实际断言是最快的方法:

start() ->
    A = generate_list(),
    assert_loop(A).

assert_loop(A) ->
    ok = do_stuff(),
    A = generate_list(),
    assert_loop(A).

上面的assert_loop/1函数强制断言 generate_list/0的输出仍然是A。没有人知道系统中可能发生的其他事情是哪些可能影响了该函数的结果,但如果返回的列表与<{1>}的值完全相同,那么行A = generate_list() 将崩溃

事实上,无论我们在上面执行A多少次,都无法无法更改此示例中的A

现在考虑一种不同的风格:

assert_loop/1

在这里,我们给了自己选择除崩溃之外的其他事情,但效果最终是相同的,因为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 的断言,=的等效性测试或==的匹配测试而不是使用=:=。为什么?因为一旦遇到不匹配的元素,这些测试就会返回 false - 如果这个不匹配发生在列表的开头附近,那么完全避免两个列表的完全遍历。 / p>

如果预期检查会更频繁地通过,那么像erlang:phash2/1这样的东西会更快,但只有如果列表很长,因为每次迭代只会完全遍历一个列表(已经存储了原始列表的哈希值)。但是,在一个简短的列表中,有可能简单的比较仍然比计算哈希,存储它,计算另一个哈希,然后比较哈希(显然)更快。因此,与往常一样,基准

phash2版本可能如下所示:

erlang:phash2/1

同样,这是一个断言循环,它将崩溃而不是干净地退出,因此需要根据您的需要进行调整。

但基本的谜团仍然存在:在一种具有不可变变量的语言中,为什么你不知道某些东西是否会发生变化?这几乎可以肯定是程序中其他地方的基础架构问题的症状 - 或者只是对Erlang中不变性的误解。