In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

わざと偏りをつけたランダムな配列の並び替え

Array.sortが元Arrayを変更することを忘れてた。
sliceでクローンを作ってからシャッフルしたら偏りが顕著に。
分布をわざと偏らせてみました
Get Adobe Flash player
by 9re 08 Oct 2009
/**
 * 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;
			});
		}

	}
}