web-dev-qa-db-ja.com

JSON配列から重複オブジェクトを削除する

次のような配列があります。

_var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];
_

そして、このようなものが残るように、重複を削除する必要があります:

_var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];
_

Underscore.jsをインストールし、._ uniqを使用してみましたが、単一の_key:value_ペアがオブジェクトに表示される場合にのみ機能するようです。複数のキーで機能するように思えません。

私が次のようなことをしようとすると:

_var uniqueStandards = _.uniq(standardsList, function(item, key, Domain){
    return item.Domain;
});
_

最初の3つの一意の値(グレードごとに1つ)のみを取得します。しかし、グレードとドメインの両方で一意の値がすべて必要です。 _.uniq関数に両方のキーを渡す簡単な方法はありますか?

最終的に、HTMLページに渡すには、ヘッダーとして一意の各グレードを、リストアイテムとして一意のドメインを含むリストが必要です。私はこれについて間違っているかもしれないので、その最終目標を達成するためのより簡単な方法があれば、私はアイデアを受け入れます。

前もって感謝します!

編集:良い反応を得て、私の最終目標が何であるかを明確にしたかった。次の形式のHTMLで一連のリストを作成しようとしています。

_<div>
    <h3>Math K</h3>
    <li>Counting & Cardinality</li>
    <li>Geometry</li>
</div>
<div>
    <h3>Math 1</h3>
    <li>Counting & Cardinality</li>
    <li>Orders of Operation</li>
</div>
<div>
    <h3>Math 2</h3>
    <li>Geometry</li>
</div>
_

私の元は、配列を作成し、$("#divid").append(array)でページ上の_<div>_要素にプッシュすることでした

30
dchess

最終的に、HTMLページに渡すには、ヘッダーとして一意の各グレードを、リストアイテムとして一意のドメインを含むリストが必要です。私はこれについて間違っているかもしれないので、その最終目標を達成するためのより簡単な方法があれば、私はアイデアを受け入れます。

したがって、実際にあなたが尋ねた形式の出力配列は必要ありません。

その場合、私は非常にシンプルで効率的な解決策で直接追跡します:

_var grades = {};
standardsList.forEach( function( item ) {
    var grade = grades[item.Grade] = grades[item.Grade] || {};
    grade[item.Domain] = true;
});

console.log( JSON.stringify( grades, null, 4 ) );
_

結果のgradesオブジェクトは次のとおりです。

_{
    "Math K": {
        "Counting & Cardinality": true,
        "Geometry": true
    },
    "Math 1": {
        "Counting & Cardinality": true,
        "Orders of Operation": true
    },
    "Math 2": {
        "Geometry": true
    }
}
_

このアプローチの興味深い点の1つは、非常に高速であることです。複数のパスを必要とする他のソリューションとは異なり(入力を自分で記述するか、_.uniq()が行うかどうか)、入力配列を1回だけパスすることに注意してください。少数のアイテムの場合、これは重要ではありませんが、リストが大きい場合は注意が必要です。

そして、このオブジェクトを使用すると、コードを実行したり、必要な他の形式を生成したりするために必要なものがすべて揃いました。たとえば、前述の正確な配列出力形式が必要な場合は、次を使用できます。

_var outputList = [];
for( var grade in grades ) {
    for( var domain in grades[grade] ) {
        outputList.Push({ Grade: grade, Domain: domain });
    }
}

JSON.stringify( outputList, null, 4 );
_

これはログに記録されます:

_[
    {
        "Grade": "Math K",
        "Domain": "Counting & Cardinality"
    },
    {
        "Grade": "Math K",
        "Domain": "Geometry"
    },
    {
        "Grade": "Math 1",
        "Domain": "Counting & Cardinality"
    },
    {
        "Grade": "Math 1",
        "Domain": "Orders of Operation"
    },
    {
        "Grade": "Math 2",
        "Domain": "Geometry"
    }
]
_

Rai は、このコード行がどのように機能するかをコメントで尋ねます。

_var grade = grades[item.Grade] = grades[item.Grade] || {};
_

これは、オブジェクトプロパティを取得したり、プロパティが見つからない場合にデフォルト値を提供したりするための一般的なイディオムです。 _=_の割り当ては右から左の順序で行われることに注意してください。したがって、ifステートメントと一時変数を使用するように文字通り変換できます。

_// Fetch grades[item.Grade] and save it in temp
var temp = grades[item.Grade];
if( ! temp ) {
    // It was missing, so use an empty object as the default value
    temp = {};
}
// Now save the result in grades[item.Grade] (in case it was missing)
// and in grade
grades[item.Grade] = temp;
var grade = temp;
_

_grades[item.Grade]_が既に存在する場合、取得したばかりの値を取得して同じプロパティに格納し直すことに気付くかもしれません。もちろん、これは不要であり、おそらくこのようにコードを記述している場合は、おそらく実行しないでしょう。代わりに、あなたはそれを単純化します:

_var grade = grades[item.Grade];
if( ! grade ) {
    grade = grades[item.Grade] = {};
}
_

これは、同じコードを記述するための完全に合理的な方法であり、より効率的です。また、_||_イディオムが依存する "真偽"よりも具体的なテストを行う方法も提供します。たとえば、if( ! grade )の代わりに、if( grade === undefined )を使用できます。

16
Michael Geary
function arrUnique(arr) {
    var cleaned = [];
    arr.forEach(function(itm) {
        var unique = true;
        cleaned.forEach(function(itm2) {
            if (_.isEqual(itm, itm2)) unique = false;
        });
        if (unique)  cleaned.Push(itm);
    });
    return cleaned;
}

var standardsList = arrUnique(standardsList);

[〜#〜] fiddle [〜#〜]

これは戻ります

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

まさにあなたが求めたものはどれですか?

24
adeneo

私はすでに多くの答えがあることを知っていますが、複雑なjson構造のために私のために働いた最高の答えは次のとおりです:

var arr = [{ "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RWCW", "desc": "WEST", "code": "RWCW", "level": 0, "save": "RWCW : WEST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RCSW", "desc": "SOUTHWEST", "code": "RCSW", "level": 0, "save": "RCSW : SOUTHWEST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RCNW", "desc": "MIDWEST", "code": "RCNW", "level": 0, "save": "RCNW : MIDWEST", "attribute1": "", "attribute2": "" }, { "State": "RSCW", "desc": "SOUTHEAST", "code": "RSCW", "level": 0, "save": "RSCW : SOUTHEAST", "attribute1": "", "attribute2": "" }, { "State": "RECW", "desc": "NORTHEAST", "code": "RECW", "level": 0, "save": "RECW : NORTHEAST", "attribute1": "", "attribute2": "" }];

var clean = arr.filter((arr, index, self) =>
    index === self.findIndex((t) => (t.save === arr.save && t.State === arr.State)))

console.log(clean);

chromeブラウザコンソールに直接これを試して、必要に応じて編集できます。

これが誰かの助けになることを願っています。

13
Aarchie

古い質問を復活させたが、@ adeneoの答えに繰り返しを投稿したかった。その答えは完全に一般的ですが、このユースケースではより効率的かもしれません(数千のオブジェクトの配列を使用する私のマシンでは遅いです)。比較する必要があるオブジェクトの特定のプロパティがわかっている場合は、それらを直接比較するだけです。

var sl = standardsList;
var out = [];

for (var i = 0, l = sl.length; i < l; i++) {
    var unique = true;
    for (var j = 0, k = out.length; j < k; j++) {
        if ((sl[i].Grade === out[j].Grade) && (sl[i].Domain === out[j].Domain)) {
            unique = false;
        }
    }
    if (unique) {
        out.Push(sl[i]);
    }
}

console.log(sl.length); // 10
console.log(out.length); // 5
8
James Irwin

あなたのケースのためのJavascriptソリューション:

console.log(unique(standardsList));

function unique(obj){
    var uniques=[];
    var stringify={};
    for(var i=0;i<obj.length;i++){
       var keys=Object.keys(obj[i]);
       keys.sort(function(a,b) {return a-b});
       var str='';
        for(var j=0;j<keys.length;j++){
           str+= JSON.stringify(keys[j]);
           str+= JSON.stringify(obj[i][keys[j]]);
        }
        if(!stringify.hasOwnProperty(str)){
            uniques.Push(obj[i]);
            stringify[str]=true;
        }
    }
    return uniques;
}
5
juvian

以下は私のために働く:

_.uniq(standardsList, JSON.stringify)

ただし、非常に長いリストの場合、おそらくこれは遅くなります。

3
stubailo
var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];

standardsList = standardsList.filter((li, idx, self) => self.map(itm => itm.Grade+itm.Domain).indexOf(li.Grade+li.Domain) === idx)

document.write(JSON.stringify(standardsList))

ここにそれを行う機能的な方法がありますが、それははるかに簡単です

standardsList = standardsList.filter((li, idx, self) => self.map(itm => iem.Grade+itm.domain).indexOf(li.Grade+li.domain) === idx)
2
Miguel Coder

**次のメソッドは、あなたが望む方法を行います。すべてのプロパティ値に基づいて配列をフィルタリングします。 **

    var standardsList = [
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Counting & Cardinality" },
  { "Grade": "Math K", "Domain": "Geometry" },
  { "Grade": "Math 1", "Domain": "Counting & Cardinality" },
  { "Grade": "Math 1", "Domain": "Counting & Cardinality" },
  { "Grade": "Math 1", "Domain": "Orders of Operation" },
  { "Grade": "Math 2", "Domain": "Geometry" },
  { "Grade": "Math 2", "Domain": "Geometry" }
];

const removeDupliactes = (values) => {
  let concatArray = values.map(eachValue => {
    return Object.values(eachValue).join('')
  })
  let filterValues = values.filter((value, index) => {
    return concatArray.indexOf(concatArray[index]) === index

  })
  return filterValues
}
removeDupliactes(standardsList) 

この結果

[{Grade: "Math K", Domain: "Counting & Cardinality"}

{Grade: "Math K", Domain: "Geometry"}

{Grade: "Math 1", Domain: "Counting & Cardinality"}

{Grade: "Math 1", Domain: "Orders of Operation"}

{Grade: "Math 2", Domain: "Geometry"}] 
2
saiteja

このページを偶然見つけたので、JSONオブジェクトの重複排除を行う必要がありました。ただし、短いES6ソリューション(外部​​ライブラリは不要)を使用して、これをChrome Dev Tools Snippets:

const data = [ /* any list of objects */ ];
const set = new Set(data.map(item => JSON.stringify(item)));
const dedup = [...set].map(item => JSON.parse(item));
console.log(`Removed ${data.length - dedup.length} elements`);
console.log(dedup);
2
Nomaed
var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];          

 function uniqurArray(array){
                         var a = array.concat();
                        for(var i=0; i<a.length; i++) {
                            for(var j=i+1; j<a.length; j++) {
                                if(a[i].Grade === a[j].Grade){
                                    a.splice(j--, 1);
                                }
                            }
                        }

                        return a;
                    }

    uniqurArray(standardsList) // put this js in console and you get uniq object in array
1
shehzad lakhani

この擬似コードを使用

var standardsList = [
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Counting & Cardinality"},
    {"Grade": "Math K", "Domain": "Geometry"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Counting & Cardinality"},
    {"Grade": "Math 1", "Domain": "Orders of Operation"},
    {"Grade": "Math 2", "Domain": "Geometry"},
    {"Grade": "Math 2", "Domain": "Geometry"}
];
var newArr =[]
for(var i in standardsList){
    newArr.Push(JSON.stringify(standardsList[i]))
}
var obj = {};
newArr= newArr.filter((item)=>{
    return obj.hasOwnProperty(item) ? false : (obj[item] = true);
})
standardsList.length = 0
for(var i in newArr){
    standardsList.Push(JSON.parse(newArr[i]))
}
console.log(standardsList)

私はあなたに似たサンプル配列を選択しました。オブジェクトを文字列化すると、オブジェクトを比較しやすくなります。次に、文字列を比較するだけです。

0
ashish yadav

これがes6の短いワンライナーです!

const nums = [
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC9233F2015",
  "AC9233F2015",
  "AC9233F2015",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E2",
  "AC8818E2",
  "AC8818E2",
  "AC8818E2",
  "AC9233F2015",
  "AC9233F2015",
  "AC9233F2015",
  "AC9233F2015",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E2",
  "AC8818E2",
  "AC9233F2015",
  "AC9233F2015",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  "AC8818E2",
  "AC8818E2",
  "AC8818E2",
  "AC8818E2",
  "ACB098F25",
  "ACB098F25",
  "ACB098F25",
  "ACB098F25",
  "AC8818E2",
  "AC8818E2",
  "AC8818E1",
  "AC8818E1",
  "AC8818E1",
  ]

SetはES6で導入された新しいデータオブジェクトです。 Setは一意の値のみを保存できるためです。配列を渡すと、重複する値が削除されます。

export const $uniquenums = [...new Set(nums)].sort(); 
0
Gerd