列表中的Shuffle元素(随机重排列表元素) [英] Shuffling Elements in a List (randomly re-arrange List Elements)
问题描述
在每次调用时都可以看到排列变化必须名单。
我的实现似乎工作正常,但我觉得它的时间相当长,并且增加了我的代码基础,而且我觉得这不是最好的解决方案。所以我需要一个更短的实现。这是我的实现:
-module(shuffle)。
-export([list / 1])。
-define(RAND(X),random:uniform(X))。
-define(TUPLE(Y,Z,E),erlang:make_tuple(Y,Z,E))。
list(L) - >
Len = length(L),
Nums = lists:seq(1,Len),
tuple_to_list(?TUPLE(Len,[],shuffle(Nums,L,[])) )。
shuffle([],_,Buffer) - >缓冲;
shuffle(Nums,[Head | Items],Buffer) - >
{Pos,NewNums} = pick_position(Nums),
shuffle(NewNums,Items,[{Pos,Head} | Buffer])。
pick_position([N]) - > {N,[]};
pick_position(Nos) - >
T =列表:max(Nos),
pick(Nos,T)。
pick(From,Max) - >
随机:seed(begin
(case random:seed(now())of
undefined - >
NN = element(3,now()),
{?RAND(NN),?RAND(NN),?RAND(NN)};
任何 - >任何
结束)
end
),
T2 = random:uniform(Max),
案例列表:member(T2,From)of
false - >挑(来自,最大值);
true - > {T2,From - [T2]}
end。
在shell中运行它:
F:\> erl
Eshell V5.8.4(中止与^ G)
1> C(洗牌)。
{ok,shuffle}
2>洗牌:列表([A,B,C,D,E])。
[c,b,a,e,d]
3>洗牌:列表([A,B,C,D,E])。
[e,c,b,d,a]
4>洗牌:列表([A,B,C,D,E])。
[a,b,c,e,d]
5>洗牌:列表([A,B,C,D,E])。
[b,c,a,d,e]
6>洗牌:列表([A,B,C,D,E])。
[c,e,d,b,a]
我的动机是在 STDLIB 中没有这样的功能。在我游戏的某个地方,我需要洗牌,我也需要找到解决问题的最有效的解决方案,而不仅仅是一个有效的解决方案。
可以帮助一个人创建一个更短的版本解决方案 ?可能更有效率?谢谢
请注意, karl的答案更简洁和简单。
这是一个相当简单的解决方案,虽然不一定是最高效:
-module(shuffle)。
-export([list / 1])。
list([]) - > [];
list([Elem]) - > [ELEM];
list(List) - >列表(List,length(List),[])。
list([],0,Result) - >
结果;
list(List,Len,Result) - >
{Elem,Rest} = nth_rest(random:uniform(Len),List),
list(Rest,Len - 1,[Elem | Result])。
nth_rest(N,List) - > nth_rest(N,List,[])。
nth_rest(1,[E | List],前缀) - > {E,前缀++列表};
nth_rest(N,[E | List],前缀) - > nth_rest(N-1,List,[E | Prefix])。
例如,可能会删除 ++
操作在 nth_rest / 3
中。在每次调用 random
时,不需要随机算法。当你开始你的程序时,最初种子,就像这样: random:seed(now())
。如果您为每次调用 uniform / 1
种子,您的结果将变得倾斜(尝试使用 [shuffle:list([1,2,3]) || _< - 列表:seq(1,100)]
)。
Part of my program requires me to be able to randomly shuffle list elements. I need a function such that when i give it a list, it will pseudo-randomly re-arrange the elements in the list.
A change in arrangement Must be visible at each call with the same list.
My implementation seems to work just fine but i feel that its rather long and is increasing my code base and also, i have a feeling that it ain't the best solution for doing this. So i need a much shorter implementation. Here is my implementation:
-module(shuffle). -export([list/1]). -define(RAND(X),random:uniform(X)). -define(TUPLE(Y,Z,E),erlang:make_tuple(Y,Z,E)). list(L)-> Len = length(L), Nums = lists:seq(1,Len), tuple_to_list(?TUPLE(Len,[],shuffle(Nums,L,[]))). shuffle([],_,Buffer)-> Buffer; shuffle(Nums,[Head|Items],Buffer)-> {Pos,NewNums} = pick_position(Nums), shuffle(NewNums,Items,[{Pos,Head}|Buffer]). pick_position([N])-> {N,[]}; pick_position(Nos)-> T = lists:max(Nos), pick(Nos,T). pick(From,Max)-> random:seed(begin (case random:seed(now()) of undefined -> NN = element(3,now()), {?RAND(NN),?RAND(NN),?RAND(NN)}; Any -> Any end) end ), T2 = random:uniform(Max), case lists:member(T2,From) of false -> pick(From,Max); true -> {T2,From -- [T2]} end.
On running it in shell:
F:\> erl Eshell V5.8.4 (abort with ^G) 1> c(shuffle). {ok,shuffle} 2> shuffle:list([a,b,c,d,e]). [c,b,a,e,d] 3> shuffle:list([a,b,c,d,e]). [e,c,b,d,a] 4> shuffle:list([a,b,c,d,e]). [a,b,c,e,d] 5> shuffle:list([a,b,c,d,e]). [b,c,a,d,e] 6> shuffle:list([a,b,c,d,e]). [c,e,d,b,a]
I am motivated by the fact that in the STDLIB there is no such function. Somewhere in my game, i need to shuffle things up and also i need to find the best efficient solution to the problem, not just one that works.
Could some one help build a shorter version of the solution ? probably even more efficient ? Thank you
Please note that karl's answer is much more concise and simple.
Here's a fairly simple solution, although not necessarily the most efficient:
-module(shuffle).
-export([list/1]).
list([]) -> [];
list([Elem]) -> [Elem];
list(List) -> list(List, length(List), []).
list([], 0, Result) ->
Result;
list(List, Len, Result) ->
{Elem, Rest} = nth_rest(random:uniform(Len), List),
list(Rest, Len - 1, [Elem|Result]).
nth_rest(N, List) -> nth_rest(N, List, []).
nth_rest(1, [E|List], Prefix) -> {E, Prefix ++ List};
nth_rest(N, [E|List], Prefix) -> nth_rest(N - 1, List, [E|Prefix]).
For example, one could probably do away with the ++
operation in nth_rest/3
. You don't need to seed the random algorithm in every call to random
. Seed it initially when you start your program, like so: random:seed(now())
. If you seed it for every call to uniform/1
your results become skewed (try with [shuffle:list([1,2,3]) || _ <- lists:seq(1, 100)]
).
这篇关于列表中的Shuffle元素(随机重排列表元素)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!