2012-01-11 24 views
11

Programımın bir kısmı, liste öğelerini rastgele karıştırmamı gerektiriyor. Bir listeye ihtiyacım olduğunda, listedeki öğeleri rasgele yeniden düzenleyecektir.
Zorunlu numaralı aranjmandaki bir değişiklik aynı arama listesindeki her aramada görülebilir.

Uygulamam düzgün çalışıyor gibi görünüyor, ancak oldukça uzun olduğunu ve kod tabanımı artırdığını hissediyorum ve ayrıca bunun için en iyi çözümün olmadığını hissediyorum. Bu yüzden çok daha kısa bir uygulamaya ihtiyacım var. kabuğunda çalıştırmaya üzerindeListedeki Karıştırıcı Elemanları (Liste Öğelerini rastgele bir şekilde yeniden düzenleyin)

 
-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. 

:

 
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] 
Ben stdlib böyle bir işlevi var olduğu gerçeğini motive ediyor İşte benim uygulamasıdır. Oyunumun bir yerinde, işleri karıştırmam gerekiyor ve aynı zamanda işe yarayan bir problem değil, problem için en iyi çözümü bulmam gerekiyor.

Bazı yardımlar çözümün daha kısa bir sürümünü oluşturabilir mi? Muhtemelen daha verimli?

cevap

4

Lütfen karl's answer'un daha kısa ve basit olduğunu unutmayın.


İşte rağmen ille en verimli değil, oldukça basit bir çözüm: Örneğin

-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]). 

, biri muhtemelen uzakta nth_rest/3 yılında ++ operasyonla yapabilirdi. Her çağrıda rastgele algoritmayı random'a tohumlamanız gerekmez. Başlangıçta programınızı başlattığınızda tohumlayın, şu şekilde: random:seed(now()). Her çağrı için uniform/1'a göre tohumlarsanız, sonuçlarınız çarpık olur ([shuffle:list([1,2,3]) || _ <- lists:seq(1, 100)] ile deneyin).

+0

Teşekkürler @Adam harika bir çözüm. Onu seviyorum –

+0

merhaba. 'random: uniform' kullanmadan önce tohum eklemeniz gerektiğini ekleyebilir miyim? aksi halde aynı sonuçları sanal makinenin farklı uygulamalarında elde edersiniz ve birçok uygulamada bu istenmeyendir. – user601836

+0

@ user601836 İyi gelin! Her işlem için yalnızca bir kez yapmanız gerektiğini ve her shuffle: list/1' için değil. –

68
1> L = lists:seq(1,10). 
[1,2,3,4,5,6,7,8,9,10] 

Her bir X öğesindeki L ile rasgele bir sayıyı R, {R, X} öğelerinin bir listesini yaparak ilişkilendirin. (: Seq (1, 10) listeleri)> karıştır - sırala listesini ve dizilerini paketten L.

bir karıştırılan bir sürümünü
1> [X||{_,X} <- lists:sort([ {random:uniform(), N} || N <- L])]. 
[1,6,2,10,5,7,9,3,8,4] 
2>  
+0

Oy verdi !, bunu da seviyorum! Teşekkürler @karl –

+0

Karıştırmanın bu yöntemi, rastgele sayı üretilmediğini garanti etmedikçe yanlı sonuçlar üretir ("rastgele: tekdüze/0" ile yapamazsınız.) – jvf

1
-module(shuffle). 

-compile(export_all). 

shuffle(L) -> 
    shuffle(list_to_tuple(L), length(L)). 

shuffle(T, 0)-> 
    tuple_to_list(T); 
shuffle(T, Len)-> 
Rand = random:uniform(Len), 
A = element(Len, T), 
B = element(Rand, T), 
T1 = setelement(Len, T, B), 
T2 = setelement(Rand, T1, A), 
shuffle(T2, Len - 1). 

ana() olsun.

+0

teşekkürler @BlackMamba –

İlgili konular