erlang乱序一个List的方案
其实我希望有人能一起来学习或讨论。
今日题目: 乱序一个List.
方法一: 一个较为精巧的乱序方案。
[php]
-module(shuffle).
-export([do/1]).
do(L) ->
Len = length(L),
NL = lists:map(fun(X) -> {random:uniform(Len), X} end, L),
NLL = lists:sort(NL),
[ V || {_,V}
其实这个问题挺困扰我的,变量一旦被赋值便不可修改,这个特性让原本写程序的想法和思路完全不同了。我上面的做法是,利用随机数生成一个[{Rand1,Elem1},...,{RandN,ElemN}]这样的列表。
然后再用sort排序后,重新打印出Elem出来,乱序的效果由此达到。
结果大概如下:
[php]
45> c(shuffle).
{ok,shuffle}
46> shuffle:do([1,2,3,4,5]).
[4,5,1,2,3]
47> shuffle:do([1,2,3,4,5]).
[2,1,5,3,4]
48> shuffle:do([1,2,3,4,5]).
[3,1,2,4,5]
49> shuffle:do([1,2,3,4,5]).
[1,5,2,3,4]
50> shuffle:do([1,2,3,4,5]).
[5,1,4,3,2]
51>
方法二:通用洗牌算法
接上文,乱序一个List,我想原有的通用洗牌算法可行的。尝试写了另一个函数。经测试有效,但是我想肯定有优化的空间。代码的风格仍然透露着浓重的过程式思想吧。
%使用洗牌算法的方案
[php]
do2(L) ->
do2(L,[]).
do2([],L) ->
L;
do2(L1,L2) ->
%io:format("L1=~w L2=~w~n",[L1,L2]),
Len = length(L1),
if
Len > 1 ->
NL = lists:split(random:uniform(Len-1), L1),
{[H1|T1],[H2|T2]} = NL,
NL2 = lists:flatten([T1],[H1|T2]),
L11 = lists:append(L2,[H2]),
do2(NL2, L11);
true ->
do2([],lists:append(L2,L1))
end.
其结果为:
128> c(shuffle).
{ok,shuffle}
129> shuffle:do2(lists:seq(0,9)).
[9,2,5,1,8,0,7,3,6,4]
130> shuffle:do2(lists:seq(0,9)).
[8,3,6,5,7,4,9,0,2,1]
131> shuffle:do2(lists:seq(0,9)).
[5,3,7,8,1,9,0,6,2,4]
132> shuffle:do2(lists:seq(0,9)).
[3,0,5,2,1,6,8,4,9,7]
133>
有几点值得思考的,关于这两种方案,是否是真正的洗牌算法。每个数字出现在某个位置是否等概率呢。
还有其它的方法不,欢迎探讨。