Erlang:检查重复插入的元素
Erlang: check duplicate inserted elements
我想知道插入的元素是否重复。
这是我正在寻找的简单示例:
首先运行应该return false。
check_duplicate("user", "hi").
但是第二个 运行 应该 return 为真。
check_duplicate("user", "hi").
函数式编程的最佳特性之一是纯函数。甚至还有像 Haskell 这样的函数式语言,你不能在其中编写不纯的函数。纯函数总是 returns 相同参数的相同值。一个不纯的函数有副作用,并且可以 return 相同参数的不同结果。这意味着必须改变一些你看不到的状态作为函数的参数。你只是在要求它。 Erlang 允许你这样做。你有很多选择如何去做。最干净的就是发送消息和从另一个进程接收消息。 (无论如何它都是不纯的,但在 Erlang 中是惯用的。下面的代码非常简单,不能用于生产。您应该使用 OTP 行为和设计原则。)
has_dupes(Jid, Text) ->
Ref = make_ref(),
seen ! {Ref, self(), {Jid, Text}},
receive {Ref, Result} -> Result end.
start_seen() ->
spawn(fun()-> register(seen, self()), loop_seen([]) end).
loop_seen(Seen) ->
receive {Ref, From, Term} ->
case lists:member(Term, Seen) of
true ->
From ! {Ref, true},
loop_seen(Seen);
false ->
From ! {Ref, false},
loop_seen([Term|Seen])
end
end.
另一个是ets(Erlang Term Storage)的存储和读取。
has_dupes(Jid, Text) ->
(catch ets:new(seen, [set, named_table])),
not ets:insert_new(seen, {{Jid, Text}}).
但是有一个问题。 table 由进程拥有,并在进程终止时被删除。它的名字是全局的等等。另一个更脏的是从进程字典中存储和读取值。
has_dupes(Jid, Text) ->
case get({Jid, Text}) of
undefined ->
put({Jid, Text}, seen),
false;
seen ->
true
end.
但这很讨厌,您几乎不应该使用这样的代码。在大多数情况下,您应该使用显式状态
new_seen() -> [].
has_dupes(Jid, Text, Seen) ->
Term = {Jid, Text},
case lists:member(Term, Seen) of
true -> {true, Seen};
false -> {false, [Term|Seen]}
end.
这是大多数时候的最佳解决方案,因为它是一个纯函数。您可以使用更好的数据结构,例如 sets
和 maps
,以便在需要观察更多术语时获得更好的性能。
我想知道插入的元素是否重复。
这是我正在寻找的简单示例:
首先运行应该return false。
check_duplicate("user", "hi").
但是第二个 运行 应该 return 为真。
check_duplicate("user", "hi").
函数式编程的最佳特性之一是纯函数。甚至还有像 Haskell 这样的函数式语言,你不能在其中编写不纯的函数。纯函数总是 returns 相同参数的相同值。一个不纯的函数有副作用,并且可以 return 相同参数的不同结果。这意味着必须改变一些你看不到的状态作为函数的参数。你只是在要求它。 Erlang 允许你这样做。你有很多选择如何去做。最干净的就是发送消息和从另一个进程接收消息。 (无论如何它都是不纯的,但在 Erlang 中是惯用的。下面的代码非常简单,不能用于生产。您应该使用 OTP 行为和设计原则。)
has_dupes(Jid, Text) ->
Ref = make_ref(),
seen ! {Ref, self(), {Jid, Text}},
receive {Ref, Result} -> Result end.
start_seen() ->
spawn(fun()-> register(seen, self()), loop_seen([]) end).
loop_seen(Seen) ->
receive {Ref, From, Term} ->
case lists:member(Term, Seen) of
true ->
From ! {Ref, true},
loop_seen(Seen);
false ->
From ! {Ref, false},
loop_seen([Term|Seen])
end
end.
另一个是ets(Erlang Term Storage)的存储和读取。
has_dupes(Jid, Text) ->
(catch ets:new(seen, [set, named_table])),
not ets:insert_new(seen, {{Jid, Text}}).
但是有一个问题。 table 由进程拥有,并在进程终止时被删除。它的名字是全局的等等。另一个更脏的是从进程字典中存储和读取值。
has_dupes(Jid, Text) ->
case get({Jid, Text}) of
undefined ->
put({Jid, Text}, seen),
false;
seen ->
true
end.
但这很讨厌,您几乎不应该使用这样的代码。在大多数情况下,您应该使用显式状态
new_seen() -> [].
has_dupes(Jid, Text, Seen) ->
Term = {Jid, Text},
case lists:member(Term, Seen) of
true -> {true, Seen};
false -> {false, [Term|Seen]}
end.
这是大多数时候的最佳解决方案,因为它是一个纯函数。您可以使用更好的数据结构,例如 sets
和 maps
,以便在需要观察更多术语时获得更好的性能。