わざと偏りをつけたランダムな配列の並び替え
Array.sortが元Arrayを変更することを忘れてた。
sliceでクローンを作ってからシャッフルしたら偏りが顕著に。
分布をわざと偏らせてみました
/**
* Copyright 9re ( http://wonderfl.net/user/9re )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rH35
*/
// forked from 9re's forked from: forked from: forked from: 1行でArrayをシャッフルする
// forked from nemu90kWw's forked from: forked from: 1行でArrayをシャッフルする
// forked from uwi's forked from: 1行でArrayをシャッフルする
// forked from nemu90kWw's 1行でArrayをシャッフルする
// Array.sortが元Arrayを変更することを忘れてた。
// sliceでクローンを作ってからシャッフルしたら偏りが顕著に。
// 分布をわざと偏らせてみました
package
{
import flash.display.*;
import flash.text.*;
import flash.events.*;
[SWF(width="465", height="465", backgroundColor="#ffffff")]
public class ShuffleArray extends Sprite
{
private var textfield:TextField = new TextField();
private var textfield2:TextField = new TextField();
private var button:Sprite = new Sprite();
private var buttontext:TextField = new TextField();
function ShuffleArray()
{
textfield.x = 10;
textfield.y = 40;
textfield.width = 465 - 10;
textfield.height = 465 - 50;
textfield.defaultTextFormat = new TextFormat("_等幅");
addChild(textfield);
button.x = 10;
button.y = 10;
button.mouseChildren = false;
button.buttonMode = true;
button.graphics.lineStyle(1, 0xBBBBBB);
button.graphics.beginFill(0xEEEEEE);
button.graphics.drawRoundRect(0, 0, 100, 20, 5, 5);
button.graphics.endFill();
addChild(button);
buttontext = new TextField();
buttontext.width = 100;
buttontext.height = 20;
buttontext.htmlText = "<p align='center'><font face='_sans'>再計算</span></p>";
button.addChild(buttontext);
button.addEventListener(MouseEvent.CLICK, function(e:Event):void{test();});
test();
}
private function test():void
{
var i:int, array:Array, text:String = "", text2:String = "";
var N : int = 100000;
var str:String;
var xi2 : Number = 0.0;
text2 += "わざと分布をばらつかせたもの\n\n";
text2 += "◆シャッフルのテスト\n";
array = new Array();
for(i = 1; i <= 10; i++) {array.push(i);}
text2 += "array = ["+array+"]\n\n";
text2 += shuffle_new(array)+"\n";
text2 += shuffle_new(array)+"\n";
text2 += shuffle_new(array)+"\n";
text2 += shuffle_new(array)+"\n";
text2 += shuffle_new(array)+"\n";
text2 += "\n◆分布のテスト\n\n";
array = [1, 2, 3, 4];
var perm:Array = permutation(array);
var result:Object = { };
perm.forEach(function(a:Array, i:int, b:Array):void {
result[a] = 0;
});
for(i = 0; i < N; i++) {result[shuffle_randomize(array)]++;}
xi2 = 0.0;
i = 0;
var m:Number;
for (str in result) {
if (result[str])
++i;
}
m = N / i;
i = 0;
perm.forEach(function(a:Array, i:int, b:Array):void {
str = a.toString();
text2 += "[" + str + "] = " + formatString(result[str], 4) + ((++i % 4 == 0) ? "\n" : " ");
if (result[str])
xi2 += (result[str] - m) * (result[str] - m) / m;
});
text2 += "\n0以外の部分のχ^2=" + xi2 + "\n";
textfield.text = text2;
return;
}
public function shuffle_new(array:Array):Array
{
for(var j:int, t:Number, i:int = array.length, a:Array = array.slice();i; j = Math.random() * i, t = a[--i], a[i] = a[j], a[j] = t);return a;
}
public function shuffle_randomize(array:Array):Array
{
var t:Number = 1;
var a:Array;
while (t > 0.5)
t = test_array(a = shuffle_new(array));
return a;
}
public function test_array(arr:Array):Number {
var count:int = 0;
for (var i:int = 0; i < arr.length - 1; ++i)
if (arr[i] + 1 == arr[i + 1])
++count;
return (arr.length - 1) ? (count / (arr.length - 1)): 0;
}
public function shuffle_original(array:Array):Array
{
return array.slice().sort(function():int{return int(Math.random() * 3) - 1;});
}
public function shuffle(array:Array):Array
{
return array.slice().sort(function():int{return Math.random() > 0.5 ? 1 : -1;});
}
private function formatString(str:String, n:int):String {
for (var i:int = str.length; i < n; ++i)
str = " " + str;
return str;
}
/**
* @param arr [1, 2, 3]などの配列を渡す
* @return arrの順列を要素に持つ配列。arr=[1,2]なら[[1,2],[2,1]]
*/
private function permutation(arr:Array):Array {
var res:Array = [];
switch (arr.length) {
case 0:
res.push([]);
break;
default:
arr.forEach(function (i:int, j:int, a:Array):void {
res = res.concat(unshiftElementToEachArray(i, permutation(removeIndexAt(j, a))));
});
}
return res;
}
/**
* @param index
* @param array
* @return arrayのindex番目だけの要素を取り除いた配列を返す
*/
private function removeIndexAt(index:*, array:Array):Array {
return array.slice(0, index).concat(array.slice(index + 1));
}
/**
* @param element 追加する要素
* @param array 配列の配列
* @return arrayに入っている配列全てに最初にelementを追加した配列を返す
*/
private function unshiftElementToEachArray(element:*, array:Array):Array {
return array.map(function(eachArray:Array, i:int, a:Array):Array {
eachArray.unshift(element);
return eachArray;
});
}
}
}