前一段時間,有同事問Erlang中如何實現將一個列表中元素打亂,我第一反應就是每次根據列表長度隨機出一個下標,將該元素剔出列表,加入到新列表中,重複上面步驟至原列表爲空便可。沒過多久一個同事說,直接給每一個元素一個隨機值,而後排序一下就能夠了。其實遊戲中常常會遇到這種須要打亂順序的狀況,例如洗牌,網上搜尋了一番,發現了些作法。java
參考 http://erlangdisplay.iteye.com/blog/380774 中的算法
版本1(速度快,隨機化很差):數組
shuffle_v1(L) -> List1 = [{random:uniform(), X} || X <- L], List2 = lists:keysort(1, List1), [E || {_, E} <- List2].
上面的版本2 代碼很多,是叫Fisher-Yates shuffle算法,根據http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle中描述,跟我開始想的方法差很少,但原算法涉及到數組的元素交換,我我的感受erlang的list在這方面不太方便,果真有更加簡潔的方案,dom
http://en.literateprograms.org/Fisher-Yates_shuffle_(Erlang) code
shuffle(List) -> shuffle(List, []). shuffle([], Acc) -> Acc; shuffle(List, Acc) -> {Leading, [H | T]} = lists:split(random:uniform(length(List)) - 1, List), shuffle(Leading ++ T, [H | Acc]).
固然原算法進行數組的元素交換,只須要一個臨時變量便可完成隨機數組的生成,特別當數組長度很大的狀況下,能節省很多內存。orm