表示調整
閉じる
挿絵表示切替ボタン
▼配色
▼行間
▼文字サイズ
▼メニューバー
×閉じる

ブックマークに追加しました

設定
0/400
設定を保存しました
エラーが発生しました
※文字以内
ブックマークを解除しました。

エラーが発生しました。

エラーの原因がわからない場合はヘルプセンターをご確認ください。

204/210

TypeScriptで2つのJSONを比較して同じものかを調べるコードを書いてみた

2023/11/03 09:22

誤り発見です。

オブジェクトのある部分の値が共にnullの場合、キーが存在しないと誤判定されます。


例:

obj1={"aa":null}

obj2={"aa":null}

これはobj1に存在するものがobj2に存在するかの判定を”==undefined”で判定している結果です。

値がnullの場合、”==undefined”の判定はtrueになりますので、nullのケースを除外する必要があります。


前の投稿から時間がかかりましたが2つのJSONを比較して同じものかを調べるコードを書いてみました。


注意点としては、

・ionicでhome.page.ts内で記述したので"function"が記載されていない

・javasciptで使用するならば、型の宣言関係("as any"とか":0bject"とか)を除外すれば動くかも?

 (こちらはテストしていないです)


それなりにテストはしましたが、実際に使われる場合は十分なテストを行って問題があれば修正してください。


戻り値のオブジェクトrtnObj["result"]がtrueならば等しくfalseならば異なるJSONです。


最初に差異が見つかった場所は、rtnObj["AccessKey"]で配列として返します。

例えば、

obj1={"a":[1,2,3,4],"b":{},"c":[5,7]}

obj2={"c":[5,7],"a":[1,2,99,4],"b":{}}

ならば

rtnObj["AccessKey"]= ["a","2"]

となり、

obj1["a"]["2"]=3

obj2["a"]["2"]=99

で異なる事が判ります。

(注意点:JSONのキーの部分は配列のインデックスである数値も文字列して扱われます。ですので配列かどうかのチェックは必須です。)

-----------------------------------


fnEquql2JSON(obj1:any, obj2:any, strict=true):object{ //strictはオプション引数。falseならば文字列"1"と数値1は同じものとして扱う。

let arrAccessKey=[] as any;

const typeObj1=typeof(obj1)

const typeObj2=typeof(obj2)

const nullObj1=(obj1==null)

const nullObj2=(obj2==null)

const arrayObj1=Array.isArray(obj1)

const arrayObj2=Array.isArray(obj2)

let rtnObj={

"result":true, "type of obj1":typeObj1, "type of obj2":typeObj2,

"obj1 is null":nullObj1, "obj2 is null":nullObj2,

"obj1 is Array":arrayObj1, "obj2 is Array":arrayObj2,

"strict":strict,

"desc":"", "AccessKey":arrAccessKey,"loop counter":0

};


try {

const isTest=false;

let cntloop=0;


//初期チェック

//単純比較(ともにnullなども含む)

if(strict){

if(obj1===obj2){

rtnObj["result"]=true;

rtnObj["desc"]='obj1===obj2';

return rtnObj;

}

}else{

if(obj1==obj2){

rtnObj["result"]=true;

rtnObj["desc"]='obj1==obj2';

return rtnObj;

}

}


switch (typeObj1) {

case "string":

case "number":

case "boolean":

case "undefined":

case "bigint":

case "symbol": //https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol

case "function":

if(typeObj1==typeObj2){

rtnObj["result"]=false;

rtnObj["desc"]="obj1 and obj2 are different values";

return rtnObj;

}else{

rtnObj["result"]=false;

rtnObj["desc"]="obj1 and obj2 are different types";

return rtnObj;

}


case "object":

//nullで等しいケースは除外済みだが片方のみnullはありえる

if(nullObj1||nullObj2){

rtnObj["result"]=false; //等しいケースは除外済み

rtnObj["desc"]="One is null, the other is not";

return rtnObj;

}

//Array?

if(arrayObj1!=arrayObj2){

rtnObj["result"]=false; //等しいケースは除外済み

rtnObj["desc"]="One is an array, the other is an Object";

return rtnObj;

}

//key

if(Object.keys(obj1).length!=Object.keys(obj2).length){

rtnObj["result"]=false;

rtnObj["desc"]="Different number of keys";

return rtnObj;

}

if(Object.keys(obj1).length==0){ //少なくとも一つは要素を持つ

rtnObj["result"]=true;

rtnObj["desc"]="Note: This object has no keys";

return rtnObj;

}


break;


default: //予期せぬエラー

rtnObj["result"]=false;

rtnObj["desc"]="switch (typeObj1) {";

return rtnObj;

}


//各階層には複数あるいは一つのBlockが存在する。チェックするのは一度に一つのみ

let key1=Object.keys(obj1);

let chkBlockIndex=0; //Keyのないケースは初期チェックで除外済み(等しい、等しくないにかかわらず)

let BlockLength=key1.length; //隣接のBlockの数(経路が変われば異なる算出が必要)

let arrCheckInfo=[]as any;

let arrTemp=[obj1, obj2, chkBlockIndex, BlockLength, key1];

//obj1, obj2 : 比較すべきobjあるいはArrayあるいは値

//chkBlockIndex, BlockLength : 検査するブロック内インデックスとブロックの保持する項目の数

//key1 : ブロック各項目にアクセスするキー配列(ex. obj1[key1[chkBlockIndex]])

//上記項目を階層ごとに作成してarrCheckInfoにpush

arrCheckInfo.push(arrTemp);


//初回のキーの存在チェック(obj2)

//if(obj2[arrCheckInfo[0][4][arrCheckInfo[0][2]]]==undefined){前書き参照

if(obj2[arrCheckInfo[0][4][arrCheckInfo[0][2]]]==undefined && obj2[arrCheckInfo[0][4][arrCheckInfo[0][2]]]!=null){


rtnObj["result"]=false;

rtnObj["desc"]="obj2 does not have key "+arrCheckInfo[0][4][arrCheckInfo[0][2]];

arrAccessKey=[];

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}


let lastindex=arrCheckInfo.length-1;

//Loop

let flg1stLoop=true; //最初のループ

let flgLoopNext=true; //falseになるまでLoop

do {

lastindex=arrCheckInfo.length-1;

rtnObj["loop counter"]++;


//for test

if(isTest){

cntloop++;

if(cntloop>5){

rtnObj["result"]=false;

rtnObj["desc"]="for test : cntloop>5";

return rtnObj;

}

}


if(arrCheckInfo[lastindex][2]>arrCheckInfo[lastindex][3]-1 && !flg1stLoop){

//初回のループで無く、このブロックの要素の最後がチェック済み

if(lastindex<=0){ //flg1stLoop=falseなので初回ではない(初回ブロック数1はあり得る)

//最上位の階層ならばブロックは一つのみ、ゆえにすべてのチェックが終了

rtnObj["result"]=true;

rtnObj["desc"]="Check completed!";

flgLoopNext=false; //チェック終了(obj1とobj2は等しい)

}else{

//同じ階層に次のブロックがなく最上位の階層でなければ、現在の階層をpopして一つ階層を上がり次のブロックの検査

arrCheckInfo.pop();

arrCheckInfo[lastindex-1][2]++; //次のループへ

}

}else{

//このブロックの比較すべき要素をチェック

let elmtemp1 : any //比較すべき要素1

let elmtemp2 : any //比較すべき要素2


arrCheckInfo.map((Element:any,index:number)=>{

if(index==0){

elmtemp1=obj1[Element[4][Element[2]]]; //インデックス番目(Element[2])のKey(Element[4])

elmtemp2=obj2[Element[4][Element[2]]];

}else{

elmtemp1=elmtemp1[Element[4][Element[2]]]; //インデックス番目(Element[2])のKey(Element[4])

elmtemp2=elmtemp2[Element[4][Element[2]]];

}

})


//undefined obj1にあるキーがobj2に存在しない

//if(elmtemp2==undefined){前書き参照

if(elmtemp2==undefined && elmtemp2!=null){


rtnObj["result"]=false;

rtnObj["desc"]="obj2 does not have key "+arrCheckInfo[lastindex][4][arrCheckInfo[lastindex][2]];

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}


const typetemp1=typeof(elmtemp1);

//要素チェック

switch (typetemp1) {

case "string":

case "number":

case "boolean":

case "undefined":

if(strict){

if(elmtemp1!==elmtemp2){

rtnObj["result"]=false;

rtnObj["desc"]="property1!==property2";

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}

}else{

if(elmtemp1!=elmtemp2){

rtnObj["result"]=false;

rtnObj["desc"]="property1!=property2";

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}

}

//次の要素の検査へ

arrCheckInfo[lastindex][2]++; //次のループへ

break;


case "bigint":

case "symbol": //https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Symbol

case "function":

//この3種類はJSONの仕様上ありえない

rtnObj["result"]=false;

rtnObj["desc"]="unexpected error : typeof(elmtemp1) = "+elmtemp1

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;


case "object":

//null

if((elmtemp1==null)!=(elmtemp2==null)){

rtnObj["result"]=false;

rtnObj["desc"]="One is null, the other is not";

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}else{

if(elmtemp1==null){ //どちらもnull

//次の要素の検査へ

arrCheckInfo[lastindex][2]++; //次のループへ

break;

}

}

//Array

if(Array.isArray(elmtemp1)!=Array.isArray(elmtemp2)){

rtnObj["result"]=false;

rtnObj["desc"]="One is Array, the other is not";

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}

//Key

const keyTemp1=Object.keys(elmtemp1);

const keyLength1=keyTemp1.length;

if(keyLength1!=Object.keys(elmtemp2).length){

rtnObj["result"]=false;

rtnObj["desc"]="The number of keys in obj1 is different from the number of keys in obj2";

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}

//arrCheckInfoに追加して次のループへ

const arrTemp=[

elmtemp1,

elmtemp2,

0,

keyLength1,

keyTemp1

];

arrCheckInfo.push(arrTemp);

break;


default: //予期せぬエラー

rtnObj["result"]=false;

rtnObj["desc"]="unexpected error"

arrAccessKey=[];

arrCheckInfo.map((el:any)=>{arrAccessKey.push(el[4][el[2]])});

rtnObj["AccessKey"]=arrAccessKey;

return rtnObj;

}

}

if(flg1stLoop){flg1stLoop=false};


} while (flgLoopNext);


return rtnObj;


} catch (error) {

rtnObj["result"]=false;

rtnObj["desc"]="try catch error : "+String(error)

return rtnObj;

}

}

評価をするにはログインしてください。
ブックマークに追加
ブックマーク機能を使うにはログインしてください。
― 新着の感想 ―
このエピソードに感想はまだ書かれていません。
感想一覧
+注意+

特に記載なき場合、掲載されている作品はすべてフィクションであり実在の人物・団体等とは一切関係ありません。
特に記載なき場合、掲載されている作品の著作権は作者にあります(一部作品除く)。
作者以外の方による作品の引用を超える無断転載は禁止しており、行った場合、著作権法の違反となります。

この作品はリンクフリーです。ご自由にリンク(紹介)してください。
この作品はスマートフォン対応です。スマートフォンかパソコンかを自動で判別し、適切なページを表示します。

↑ページトップへ