javascriptで配列をシャフルして順番をバラバラにしたいのですが、配列が3つある場合に


var data1 =["Aさん","Bさん","Cさん","Dさん"]
var data2 =["北海道","千葉","神奈川","沖縄"]
var data3 =["10歳","12歳","50歳","44歳"]
var shuffle = function() {return Math.random()-.5};
data1.sort(shuffle)

上記を実行しdata1の人名をシャフルした場合、それに紐付いたdata2(出身地)、data3(年齢)を人名にそれぞれに紐付けるにはどうしたらいいのでしょうか?
Aさんの出身地は北海道で10歳です。

data1,data2,data3をまとめてそれぞれシャフルしてしまうと、名前と、出身地と年齢もバラバラになってしまうため、シャフルしたdata1と同じ順番にそれに紐付いたdata2とdata3を並べる方法はありますか?

data1の配列の中身をシャフルしてそのシャフルした順番に合わせて
data2,data3も同じ順番にそろえたいです。

data1,2,3のそれぞれの配列同士をジョイントして、それをシャフルしたあと、もう一度配列を3つに分けて元に戻す?というやり方?? 

いいアイデアを是非教えてください。

回答の条件
  • 1人30回まで
  • 登録:
  • 終了:2016/12/21 21:35:03

回答3件)

id:cdaotg No.1

回答回数123ベストアンサー獲得回数35

ダミーの配列を用意して、それをシャッフルした後にダミーの配列の順にdata1~3を並び替えるのはどうでしょうか?

【手順】
1. data0を{0,1,2,3}で初期化する。
2. data0をシャッフルする。
3. data0の結果に応じて、data1~3を並び替える。

例えば、2.の後にdata0が{2,0,1,3}になっていたら、data1は{"Cさん","Aさん","Bさん","Dさん"}とする感じです。

id:kajironpu

ありがとうございます。なかなかこのアイデアが出てきませんでした。
ダミーの配列だけシャフルして、その順番と同じ配列の中身を
取り出すやり方ですね。さっそくコードを考えています。
ありがとうございました!

2016/12/08 09:36:35
id:pogpi No.2

回答回数428ベストアンサー獲得回数59

No1の方と同じで、インデックスだけシャッフルで、data1からdata3はシャッフルする必要ないと思いますよ。
シャッフルされた順に、
data1[data0[(インデックス)]]
data2[data0[(インデックス)]]
data3[data0[(インデックス)]]
で、インデックスを+1していけば結びついたまま取れますよ。

id:kajironpu

ありがとうございます!! さっそく試してみました。

var data1 =["Aさん","Bさん","Cさん","Dさん"]
var data2 =["北海道","千葉","神奈川","沖縄"]
var data3 =["10歳","12歳","50歳","44歳"]
var index =[];
var data1_after=[];
var data2_after=[];
var data3_after=[];

for (var i = 0; i < data1.length; i++) {
index.push(i)  //インデックスの配列に数字をつめる
}

var shuffle = function() {return Math.random()-.5};
index.sort(shuffle)

for (var i = 0; i < index.length; i++) {
data1_after.push(data1[index[i)
data2_after.push(data2[index[i)
data3_after.push(data3[index[i)
}
alert(data1_after)
alert(data2_after)
alert(data3_after)

初心者的なコードで恐縮ですが、こんな感じで試してみました。

2016/12/08 09:52:42
id:a-kuma3 No.3

回答回数4973ベストアンサー獲得回数2154

「添え字を並べ替えれば良いじゃない」という話は既に出ているので、別の視点から。


そもそも、そのシャッフルの仕方が良くないです。きれいに混ざりません。

# Qiita からの参照ページ(2番目)がアーカイブ落ちですが、混ざらない様子がよく分かります

一見、短いコードでエレガントなように見えますが、ソートのアルゴリズムによっては思った通りにならない。
安定なソートで速い、というところでライブラリはマージソートで実装されていることが多いので、あのような結果になります。
# バブルソートとか選択ソートなら、期待通りに混ざると思います

で、こうするべきだろうと書かれているコードがこうです。

Array.prototype.shuffle = function (){
    var i = this.length, j, temp;
    if ( i == 0 ) return;
    while ( --i ) {
        j = Math.floor( Math.random() * ( i + 1 ) );
        temp = this[i];
        this[i] = this[j];
        this[j] = temp;
    }
};

あるひとつと、別のもうひとつをランダムに選んで入れ替える、を繰り返します。
これは、Array のメソッドを拡張するやり方なので、自分(this)を対象にしていますが、このやり方だと複数の配列を対象にもできます。
質問のケースに合わせるとこんな感じ。

var data1 =["Aさん","Bさん","Cさん","Dさん"]
var data2 =["北海道","千葉","神奈川","沖縄"]
var data3 =["10歳","12歳","50歳","44歳"]

var i = data1.length, j, temp;
while ( --i ) {
    j = Math.floor( Math.random() * ( i + 1 ) );
    // data1
    temp = data1[i];
    data1[i] = data1[j];
    data1[j] = temp;
    // data2
    temp = data2[i];
    data2[i] = data2[j];
    data2[j] = temp;
    // data3
    temp = data3[i];
    data3[i] = data3[j];
    data3[j] = temp;
}
console.log(data1);
console.log(data2);
console.log(data3);

値の入れ替えを三つの配列に対してやっているだけです。


あと、長く付き合うプログラムなら、データの持ち方は見直した方が良いと思います。
関係する一連の情報は、近くにあった方が良い です。
「近く」というのは、こういうことです。

// 配列の配列
var data =[
    ["Aさん", "北海道", "10歳"],
    ["Bさん", "千葉",   "12歳"],
    ["Cさん", "神奈川", "50歳"],
    ["Dさん", "沖縄",   "44歳"],
];

// 連想配列の配列
var data =[
    {name: "Aさん", address: "北海道", age: "10歳"},
    {name: "Bさん", address: "千葉",   age: "12歳"},
    {name: "Cさん", address: "神奈川", age: "50歳"},
    {name: "Dさん", address: "沖縄",   age: "44歳"},
];

こうしておくと、このシャッフルの問題もひとつの値を対象にするときのロジックが素直に使えたり、例えば、年齢で並べ替えたり、というときも素直なコードで書くことができます。

id:kajironpu

a-kuma3さん、これすごいですね 複数の配列を一気に並行してできるのですね?
さっそく、今から、これを使って試してみます。
配列の並びもちょっと見直し改良を検討してみます。
いろいとありがとうございます。

2016/12/08 14:02:11

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません