0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JavaScriptで多次元配列をコピーしてシャッフル(っぽいこと)

Last updated at Posted at 2022-11-21

編集履歴

2022年11月22日: コメントでご指摘いただいたので取り急ぎタイトル変えました! 記事内容も追々編集します!
2023年8月14日: 遅まきながら、コメントいただいた分を反映しました! 半年以上たって気づいたこと(こうすればよかったんじゃない?)も追記しています。

前提

この記事は勉強中の覚え書きの要素が強いです。
ベストな方法かはともかく、私の場合はこのやり方でできたよ! というものですが、同じことで困っている人にもし役立てばうれしいです。
もっと良い方法あるよ! って場合はぜひコメントください。

とりあえずコード

test.js
function shuffle(list){
	let copyList=[];
	for ( i = list.length - 1; i >= 0; i--) {
		copyList.push(list[i]);
	}
	for ( i = copyList.length - 1; i >= 0; i--) {
		const r = Math.floor(Math.random() * (i + 1));
		const tmp = copyList[i];
		copyList[i] = copyList[r];
		copyList[r] = tmp;
	}
	return copyList;
}

const wordList = [["test","テスト"],["array","配列"],["copy","コピー"]];
let copyList = shuffle(wordList);

うーんこのゴリ押し。
新しく配列作って、pushで要素入れて、シャッフル。
前半のpushの時点で元の順序と逆になってるのは後でシャッフルするからいいか~という気持ちの表れです。
シャッフル部分は先人の方々のコードをマネしています。

ここまでにいたる道筋

何のためにこのコード書いてるの?

勉強がてら作っているタイピングゲームのためです。コピーした配列からpopで取り出しても、元の配列はそのまま残ってほしくなったので。

  1. タイピング対象の英単語と、一緒に表示する日本語訳を配列に入れたぞ! とりあえず片手で足りる数入れてテストするぞ!
  2. シャッフルして表示、正しく打てたら次の単語に移るのはできたけど、単語が尽きた後どうしようか。
  3. 今後単語数増やしても全部打ち尽くされる可能性はあるし、最後まで行ったらまたシャッフルして入れなおそう!
  4. あっ、popで配列から単語を取り出してたせいで、中身が全部なくなってシャッフルも何もできない! 元の配列からも取ってこれない! なんでだ?
  5. (調べた)ふむふむ、元の配列からコピーしてるんじゃなくて、参照先を同じにしているだけなのね。だから元の配列も空になってたんだな(ざっくり)

↑のとき書いていたコード

test.js
function shuffle(list){
	for ( i = list.length - 1; i >= 0; i--) {
		const r = Math.floor(Math.random() * (i + 1));
		const tmp = list[i];
		list[i] = list[r];
		list[r] = tmp;
	}
	return list;
}

const wordList = [["test","テスト"],["array","配列"],["copy","コピー"]];
let copyList = shuffle(wordList);

//copyListからpopで取り出して表示したりとか、キーボード打った時の動作とか

//copyListが空になったらまたシャッフルして入れなおそうとした
if(copyList.length == 0){
    copyList = shuffle(wordList); 
}

試してみてうまくできなかったやり方

調べる中でmap()メソッドがあると知りましたが、今回うまく使えませんでした。

以下、2023年8月14日追記

コメントで教えていただいたこと

スプレッド構文

MDNのドキュメント

自分用かみ砕き:配列とか文字列とかオブジェクトの中身を全部展開します。例えば、配列の中身を全部足し算したい!というときにも使えます。

元の配列からcopyListに値を全部コピーするならこれ1行で済みました。

test.js
const copyList = [...list];

ドキュメントによると、1次元配列ならこれだけで元の配列を破壊せずに済むようです。
多次元配列だと、コメントにもあったように、copyList内の要素を変更すると元の要素にも影響が出るようですね。

分割代入

MDNのドキュメント
自分用かみ砕き:配列内の要素をそれぞれ左辺の変数とかに分けて入れます。便利!

ドキュメント内の「変数の入れ替え」の項目で書かれている、分割代入を使わずに入れ替える方法(一時変数を使う)が、記事内のコードでやっていた方法ですね。

後になって気づいたこと

popで取り出すから困るのであって、取り出さずに参照する方法でもできたのでは? そっちのほうがコピー配列を作らずに済んでスマートでは? と気づきました。
その辺は書くとしたら別記事にします。
とは言え、コピーする方法を試したことで記事を書いてコメントで知見を得れたので結果オーライだと思ってます。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?