2018年12月16日日曜日

JavaScriptでPythonのrange関数っぽいものを作る

JavaScriptで連続した適当な配列を作りたい場合

const arr = [1, 2, 3, 4, 5];
でもいいですがPythonの様なrange関数でささっと作りたい場合があります。
Rangeオブジェクトは存在しますが、DOM用のオブジェクトでありPythonのものとは用途が違います。
underscore.jsで同じようなものが提供されているのでライブラリを使用するならそれがいいでしょう。

Pythonのrange関数

Pythonのrange関数はリスト(JavaScriptで言う配列)を容易に作れる関数です。
Pythonを使う方ならお馴染みでしょう。

主な仕様は、

range(0からの終了数)
range(開始数, 終了数)
range(開始数, 終了数, STEP数)

となります。引数の数によって動作が違います。


[ソース]

#! /usr/bin/env python

# -*- coding: utf-8 -*-

print("[range]")

for i in range(10):
    print(i, end=", ")
print()

for i in range(5, 10):
    print(i, end=", ")
print()

for i in range(0, 10, 2):
    print(i, end=", ")



[結果]

[range]
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
5, 6, 7, 8, 9,
0, 2, 4, 6, 8,

このような動作となります。
JavaScriptで同じような動作の関数を作ってみましょう。

ここあたり
https://dev.to/ycmjason/how-to-create-range-in-javascript-539i
を見ると、同じような考えでrange関数を作っている人がいます。

主な仕様は2番目のrange(開始数, 終了数)のようです。
Array.from() や Array.prototype.fill()を使った方法などがあるみたいです。
例にあるようなものに加え、STEP数まで加味出来る仕様にしましょう。


  function range(/* 開始数, 終了数, STEP数 */) {
    const len = arguments.length;
    const arr = [];
    let min = 0;
    let max = 0;
    let step = 1;

//引数の数により開始数と終了数を変える
    switch(len) {
      case 1:
        max = arguments[0];
      break;
      case 2:
        min = arguments[0];
        max = arguments[1];
      break;
      case 3:
        min = arguments[0];
        max = arguments[1];
        step = arguments[2];
      break;
    };

    for(let i = min; i < max; i++) {
// 第三引数があればSTEP数として処理をする
      if(step != 1) {
        if(i % step == 0) {
          arr.push(i);
        }
      }else {
        arr.push(i);
      }
    }

    return arr;
   }


//①
   const a1 = range(10);
   console.log(a1);


//②
   const a2 = range(5, 10);
   console.log(a2);


//③
   const a3 = range(1, 10, 2);
   console.log(a3);

//④
   for(let i of range2(5, 10)) {
      console.log(i);
   }


[結果]

[0,1,2,3,4,5,6,7,8,9]
[5,6,7,8,9]
[2,4,6,8]
5
6
7
8
9

レガシーな書き方ですが、こんな感じでしょうか?
④はPythonのrangeの様な使い方です。

2018年11月23日金曜日

アントワーヌ・ゴンボーの疑問をPythonで検証してみる

確率論の始まりの話でよく出てくるアントワーヌ・ゴンボーの疑問

17世紀、フランスの貴族シュバリエ・ド・メレ卿(アントワーヌ・ゴンボー)という人はギャンブル好きだった。
彼は、サイコロのギャンブルが好きで、
1つのサイコロを4回投げて、6が出れば勝ちというゲームをした時は2/3の確率で勝つと考えた。
勝率は予想に届かなったが、勝ち越すことは出来た。
そして、2つのサイコロを24回投げて、6,6のゾロ目が出れば勝ちというダブルシックスも同じように、6,6のゾロ目が出る確率は1/36なのだから24回投げれば2/3で勝てるはずと考えた。
しかし、実際は予想に反してあまり勝てなかった。
そこで、ゴンボーは数学者パスカルに、何がおかしいか相談してみた。
パスカルはゴンボーの考え違いを見抜き、出る目から計算するのでなく、出ない目から計算するのが正しいと答えたそう。

さてそれをPythonで検証してみましょう。

まずは1つのサイコロから6の目が出れば勝つというゲーム
4回投げてどれくらいの確率で勝つかrandomを使って試してみましょう。

#! /usr/bin/env python

# -*- coding: utf-8 -*-

import random

print("[probability]")

#試行回数
trial = 10000

#投げる回数
roll = 4

#勝った回数
win = 0

def dice(trial, roll):
    win = 0
    reset = False
    for i in range(trial):
        reset = False
        for j in range(roll):
            if reset == False:
                #サイの目をランダムに出す
                pip = random.randrange(1, 7)
                #目が6なら勝ち
                if pip == 6:
                    win += 1
                    reset = True
    return win

win = dice(trial, roll)
print("試行回数: ", trial)
print("勝った回数: ", win)
print("勝率: ", (win / trial))


結果:
[probability]
試行回数:  10000
勝った回数:  5218
勝率:  0.5218

[probability]
試行回数:  10000
勝った回数:  5184
勝率:  0.5184

[probability]
試行回数:  10000
勝った回数:  5140
勝率:  0.514

[probability]
試行回数:  10000
勝った回数:  5144
勝率:  0.5144

[probability]
試行回数:  10000
勝った回数:  5222
勝率:  0.5222


2/3には届きませんが勝ち越すことは出来ます。
次に、2つのサイコロを24回投げ、6,6のゾロ目が出たら勝ちというゲーム


#! /usr/bin/env python

# -*- coding: utf-8 -*-

import random

print("[probability]")

#試行回数
trial = 10000

#投げる回数
roll = 24

#勝った回数
win = 0

def dice(trial, roll):
    win = 0
    #ゲームリセットフラグ
    reset = False
    for i in range(trial):
        reset = False
        for j in range(roll):
            if reset == False:
                #サイの目をランダムに出す
                pip1 = random.randrange(1, 7)
                pip2 = random.randrange(1, 7)
                #print("({}, {})".format(pip1, pip2), end=" ")
                #目が6, 6なら勝ち
                if pip1 == 6 & pip2 == 6:
                    win += 1
                    reset = True
                    #print()

    return win

win = dice(trial, roll)
print("試行回数: ", trial)
print("勝った回数: ", win)
print("勝率: ", (win / trial))


結果:

試行回数:  10000
勝った回数:  4939
勝率:  0.4939

[probability]
試行回数:  10000
勝った回数:  4997
勝率:  0.4997

[probability]
試行回数:  10000
勝った回数:  4900
勝率:  0.49

[probability]
試行回数:  10000
勝った回数:  4957
勝率:  0.4957

[probability]
試行回数:  10000
勝った回数:  4961
勝率:  0.4961

10000万回試行した結果では勝率5割を割りました。
パスカルの計算したとおりですね。
ポイントは勝った場合にゲームリセットすることです。
これが無いと一つのゲームに複数勝利することになりますので2/3に近い数字が出ます。

パスカルの計算式
1つのサイコロを4回投げて6が出たら勝つゲームの勝率
1 - (5/6) ^4 = 0.5177469

2つのサイコロを24回投げて6, 6のゾロ目が出たら勝つゲームの勝率
1 - (35/36) ^4 = 0.491403876

実際にランダムに試行した結果も計算に近い数字が出ましたね。

2018年10月22日月曜日

XMLHttpRequestで画像を扱う

XMLHttpRequestで画像を読み込む


Ajaxで一部のWebデータを読み込む時、XMLHttpRequestを使いますが、テキストデータが主に読み込みの対象となっているので今回は画像データを読み込みたいと思います。

読み込み方はテキストと同じで、 読み込んだ画層データをBlobかArrayBufferとして処理するだけでOKです。


Blobによる読み込み



  
    
    XMLHttpRequest
  

  

XMLHttpRequest

もう一つの例



  
    
    XMLHttpRequest
  

  

XMLHttpRequest