初心者エンジニアの他愛もない質問を大好物にしている、ユゲタです。
今回の質問は、お馴染みteratailで見つけた、
質問内容
「2つのFileオブジェクトの配列を比較し、重複するデータを削除したい」
前提
JavaScriptでデータの集計システムを作っています。
配列の操作がうまく出来ず詰まっています。
実現したいこと
2つのFileオブジェクトの配列で重複するデータを削除したいです
https://developer.mozilla.org/ja/docs/Web/API/File
以下の配列を
javaScript
const array1 = [File1,File2,File3];
const array2 = [File4,File1,File2];
以下の結果に成形したいです
javaScript
const result = [File1,File2,File3,File4];
試したこと
map, filter, setで色々やってみましたが、うまく出来ませんでした・・。
setだと同じだと認定されてないみたいなので困ってます
参考 :
https://teratail.com/questions/69f0nll8igxzox
という内容で、投稿日が、2022/10/03 16:46。
このブログを書いている、2022/10/28 7:00時点で、解答は0件の状態です。
ちなみに、質問に対する質問が2件入っていて
質問1.
配列に入っている「FileX」の格納方法について明記した方がよいかと思います。
JavaScriptの仕様上「{} === {}」も「false」と判定されます。
ですが、「let a = {}; let b = a; a === b」は「true」です。
どのように格納されたかによって、判定が違ってきます。
質問2.
可能な限り実際のコードをご提示ください。
自分なりの見識
そもそもこの質問では、自分がやりたい事が書かれていて、それを解決するためのストレートな解答が単純には出来ないため、
「他の人が仕事でやるべき事を、無料質問サイトで親切丁寧に答えてやる義理は無い」
という思考で上から目線の解答ユーザーが多いこのサイトでは、なかなか答えてくれないでしょう。
ちなみに、今回の質問で足りていない内容としては、File1,File2の内容がどういったモノなのか?という内容です。
このFile1のデータの中身がjsonデータで必ず内容にid値が存在していて、そのid値を判別すればいいだけであれば、javascriptのfilter機能を使えば実現可能です。
参考 :
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
でも、恐らくこのFile1にはデータモデルを持っていないと考えられるので、その場合に、File1とFile2のデータを比較する関数を書いて、配列内のデータをそれぞれ全て比較する処理を書く必要があります。
map関数で関数記述してもいいですが、普通にfunctionで処理した方がわかりやすいプログラムになると思いますね。
javascriptのオブジェクトは何故比較が出来ないのか?
質問の質問でも書かれている、
"{} === {}"この比較が、javascriptでは、何故falseになるのかを考えてみると、
オブジェクトは、メモリデータとして扱われていて、そのメモリアドレスが違っているので、比較をしてもfalseになってしまうと考えられます。
"let a = {}; let b = a; a === b"がtrueになるのは、bには、aと同じメモリアドレスがセットされるので、参照コピーと同じ状態なので、trueが変えるという状態でしょうね。
メモリアドレスの意味がわからない人は、この説明でもわからないし、インスタンスや参照コピーなどの意味も分からないと思うので、全て文字列として考えたほうが良いかもですね。
文字列で考えるオブジェクト比較
手段の一つとして、File1などのオブジェクトを全て文字列に変換して、それを比較するという手があります。
JSON.stringify(File1) === JSON.stringify(File2)
こうしてみると、同じ内容かどうかの比較はできますが、注意点もあって、それぞれのオブジェクトの並び順が同じになっていないといけません。
const File1 = { a : 1 , b : 1}
const File2 = { b : 1 , a : 1 }
これを上記のJSON変換して、比較すると、確実にfalseが返ってきます。
Objectのkey一覧を取得して、それをソートして、そのとおりにオブジェクトを並べ直して、それをJSONに変換して、最後にそのデータを比較するという手順でやれば、想定通りに事はできるかもですね。
解答サンプルを作ってみた
const File1 = { a : 1 , b : 1}
const File2 = { b : 1 , a : 1 }
const Temp1 = Object.fromEntries(Object.keys(File1).sort().map(k => {return [k, File1[k]]}))
const Temp2 = Object.fromEntries(Object.keys(File2).sort().map(k => {return [k, File2[k]]}))
console.log(JSON.stringify(Temp1) === JSON.stringify(Temp2) ? 'same' : 'diff')
> same
無事に"same"になりました。
ちょっとだけ解説
const Temp1 = Object.fromEntries(Object.keys(File1).sort().map(k => {return [k, File1[k]]}))
この箇所が分かりにくいと思うので、解説をすると、
Object.fromEntries(...)
この命令は、配列(array)をデータ(object)に変換する命令で、[["a",1],["b",2]]こんな配列データを{a:1,b:2}というobjectにしてくれます。
これを下記の処理の結果でできたarrayに適用させています。
Object.keys(File1)
この命令を使って、objectのkey一覧を抜き出します。
sort()
抜き出したkey一覧をソートします。
map(k => {return [k, File1[k]]})
ココがポイントなんですが、objectデータを [key , value]という配列に変換するんですが、その時に、事前にsortされた一覧順番になるので、結果的にobjectのkey値ソートデータが出来上がるというわけです。
上記を一括で行って、まるでobjectのソート変換ができたという形になります。
最後に
どうですか?Javascriptに慣れている人でも、他人が書いたこういうソースは難しく見えます。
でも、objectデータをkey値で簡易ソートできる、
いわゆるPHPのksortのようなスニペットを作ることができました。
これ、他でもかなり使えるので、オススメですね。
あれ?当初の質問ってなんだっけ?
あ、同じオブジェクトを除外して、違うオブジェクトデータだけをマージしたデータを作る事だった・・・
もうしんどいから、今日はここまで!
0 件のコメント:
コメントを投稿