【解決】二次元配列の要素同士が連動(?)する条件と回避方法が分かりません。

chro
記事: 86
登録日時: 2021年2月14日(日) 11:26

Re: 【解決】二次元配列の要素同士が連動(?)する条件と回避方法が分かりません。

投稿記事by chro » 2022年12月14日(水) 20:35

それはもしかして、アイテムを入手する時、同じ配列を追加していませんか?
たぶん、次の結果はtrueになって、同じ参照だと思います。

コード: 全て選択

console.log($gameVariables.value(DBvalNum)[3] === $gameVariables.value(DBvalNum)[4]) //true
$gameVariables.value(DBvalNum)[3][2] === 1; //0でなく、1で代入される


下記やり方で追加すると、同じ参照を追加しているだけになって、質問の件の連動する状態になります。
同じ配列を追加していたから、同じアイテムIDのものが連動してしまったのが、原因だと思います。

コード: 全て選択

var items = [];
var item1 = [0,1,100,98,0,0,0];
var item2 = [0,2,100,0,0,0,0];
items.push(item1,item2,item1,item2);

items[0] === items[2]; //true
items[0][3] = 200;

items[2][3]; //200


解決方法は、
.slice()で新しい配列(単純なディープコピー)を作成するか、直接配列を指定して新たに作成します。

コード: 全て選択

var items = [];
var item1 = [0,1,100,98,0,0,0];
var item2 = [0,2,100,0,0,0,0];
items.push(item1.slice(), item2.slice(), item1.slice(), item2.slice());
items.push([0,1,100,98,0,0,0], [0,2,100,0,0,0,0]);

アバター
サブちゃんB
記事: 27
登録日時: 2018年3月06日(火) 01:09

Re: 【解決】二次元配列の要素同士が連動(?)する条件と回避方法が分かりません。

投稿記事by サブちゃんB » 2022年12月14日(水) 21:05

完全にchro様の仰るとおりでした!!

console.log($gameVariables.value(DBvalNum)[3] === $gameVariables.value(DBvalNum)[4])
は見事にtrueとなりました。

csvから読み込んだ各アイテム入手時のテーブルを二次元配列として別の$gameVariables.valueに読み込んでおいて、入手時にそこからpush()で追加しておりました。
入手時のpushに.slice()を入れると、直接参照でも正常に動作しました!

うまくいかない処理本体ばかりを見て悩んでおりましたが、まさか入手時のpush()に問題があるとは夢にも思いませんでした。
ここからしてシャローとディープを意識しないといけないとは、自力では気がつくことが出来ませんでした。
お陰様で非常に勉強になりました。
本当にありがとうございました。
アバター
サブちゃんB
記事: 27
登録日時: 2018年3月06日(火) 01:09

Re: 【解決】二次元配列の要素同士が連動(?)する条件と回避方法が分かりません。

投稿記事by サブちゃんB » 2022年12月23日(金) 20:23

名無し蛙様、chro様、先日は大変貴重な知見をご提供くださいまして、誠にありがとうございました。
お陰様で新作ゲームの開発が非常にうまくいっております。

先日chro様にご教示頂いたパターン1のコードを使って、引き続き条件が一致するアイテムの個数合算をしておりました。
ご教示頂く際に私が非常に重要な点を見落としておりました。
それは、keyIndexが複数存在することです。
想定されるkeyIndexは、0,1,3です。
つまり、1列目(インデックス0)、2列目(インデックス1)、4列目(インデックス3)が一致する場合に、3列目(インデックス2)の数値を合算したいのです。
当然ながら、1つしかないkeyIndexを1に設定した場合、インデックス0とインデックス3が一致しなくても合算されてしまいます。

相談させて頂いたときはインデックス2の値が連動することを解消することのみに注視しており、複数のkeyIndexが存在することについて認識はしていたものの、それくらいは自力で改造出来るだろうと高をくくっていましたが、甘かったです。
ご教示頂いたパターン1、パターン2を自分なりに調べて試行錯誤してみましたが、どうやら今の自分にはkeyIndexが複数存在する場合への改造は無理そうです。

幸いにして当初相談したときに自分で書いた長ったらしいコードが行追加push時の.slice()によりうまく動きましたので、理解の浅いまま追加してしまった余計なディープコピー処理を省いて、今のところなんとか間に合わせることが出来ております。
ご教示頂いたコードを元に合算処理をした方が明らかに演算が速そうなので、ご教示頂いたコードを活かした複数keyIndexの合算にもいつか挑戦してみたいと思います。
名無し蛙
記事: 308
登録日時: 2015年11月23日(月) 02:46

Re: 【解決】二次元配列の要素同士が連動(?)する条件と回避方法が分かりません。

投稿記事by 名無し蛙 » 2022年12月24日(土) 00:26

多分idの部分で処理を集約させれば帳尻合うと思いますよ。
どのような管理をしているのか知らないので断言は出来ませんが
アイテムデータベースの時点で予め一意のidを振っておいた方が管理が楽だと思いますけどね。
chro氏のコードを借りて改造するならこんな感じですか。
.toString()で配列の参照から文字列に変換する必要がある点に注意すれば、
後は特に難しい所も無いと思います。ついでにparentsも[]から{}に変更しています。

コード: 全て選択

//パターン1
const sumMakeIndexArr = function(arr, keyArray, sumIndex) {
    const parents = {};//親となる、最初に出現したIDがある配列のindex
    arr.forEach((a, i) => {
        const id = keyArray.map(keyIndex => a[keyIndex]).toString();
        let parentIndex = parents[id];
        if (parentIndex === undefined)  {
            //初めて出現するIDの場合、親として扱い、数値はそのまま
            parents[id] = i;
        } else {
            //既にIDが存在した場合は、そのindexへ加算
            arr[parentIndex][sumIndex] += a[sumIndex];
            //親へ合算したため、0を代入
            a[sumIndex] = 0;
        }
    });
};

//サンプル
var arr1= [
    [0,1,100,98,0,0,0],
    [0,2,100,98,0,0,0],
    [0,4,100, 0,0,0,0],
    [0,2,100,98,0,0,0],
    [0,3,100,0,0,0,0],
    [0,2,100,98,0,0,0],
    [1,3,100,0,0,0,0]
];
sumMakeIndexArr(arr1, [0, 1, 3], 2); // (配列, アイテムIDのindex配列, 合計するindex)
console.log(arr1);
アバター
サブちゃんB
記事: 27
登録日時: 2018年3月06日(火) 01:09

Re: 【解決】二次元配列の要素同士が連動(?)する条件と回避方法が分かりません。

投稿記事by サブちゃんB » 2022年12月24日(土) 12:58

名無し蛙 様、いつもご指導頂きありがとうございます。

ご教示頂きましたコード、見事正常に動作しました!
私が挑戦したときは引数を増やしてif文の条件を増やしてとやってうまくいかずに諦めましたが、
複数のインデックスを配列にするという手があるとは目から鱗です。
連想配列については各データの取得時に意識するのみで自分が組むコードでは積極的に使っていませんでしたが、
使いこなせるようになってスマートなコードを書いてみたいです。

この度も大変貴重な知見をご教示くださいまして、誠にありがとうございました。
今後ともご指導のほど、宜しくお願い致します。

“MZ:質問” へ戻る