之前写了一片文介绍过等概率随机取数算法的几种实现(洗牌算法),Erlang并没有内置这种函数,现在补充下Erlang版本的实现。
方法一
给每个元素加一个随机的顺序id,然后进行排序。速度快,但是随机性差。
shuffle(L) ->
List1 = [{random:uniform(), X} || X <- L],
List2 = lists:keysort(1, List1),
[E || {_, E} <- List2].
方法二 Knuth-Durstenfeld Shuffle算法
shuffle([]) ->
[];
shuffle([_] = L) ->
L;
shuffle(L) ->
shuffle_1(1, L, erlang:length(L)).
shuffle_1(Len, L, Len) ->
L;
shuffle_1(Cur, L, Len) ->
S = Cur + erlang:round((Len - Cur) * random:uniform()),
L2 = swap_element(L, Cur, S),
shuffle_1(Cur + 1, L2, Len).
swap_element(L, N, N) ->
L;
swap_element(L, N1, N2) ->
Z = lists:zip(lists:seq(1, length(L)), L),
{value, E1} = lists:keysearch(N1, 1, Z),
{value, E2} = lists:keysearch(N2, 1, Z),
Z2 = lists:keyreplace(N1, 1,
lists:keyreplace(N2, 1, Z, E1),
E2),
{_, Result} = lists:unzip(Z2),
Result.
算法详解可以看上方的链接,这个方法的随机性好,但是因为erlang的变量不可重复赋值,且List通过链表实现,导致效率比较低。