Подтвердить что ты не робот

Удалить дубликаты объектов из массива 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;
});

Я получаю только первые три уникальных значения (по одному на класс). Но мне нужны все уникальные ценности как для класса, так и для домена. Есть ли простой способ передать оба ключа функции _.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>

Моим оригиналом было создание массива и его толкание в элемент <div> на странице с $("#divid").append(array)

4b9b3361

Ответ 1

В конечном счете, мне нужен список с каждым уникальным классом в качестве заголовка и уникальных доменов в качестве элементов списка, которые нужно передать в 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
    }
}

Интересно, что этот подход очень быстрый. Обратите внимание, что он делает только один проход через входной массив, в отличие от других решений, которым требуется несколько проходов (независимо от того, записываете ли вы их самостоятельно или _.uniq() делает это для вас). Для небольшого количества элементов это не имеет значения, но хорошо иметь в виду более крупные списки.

И с этим объектом теперь у вас есть все необходимое для запуска любого кода или создания любого другого формата, который вы хотите. Например, если вам нужен точный формат вывода массива, который вы упомянули, вы можете использовать:

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

JSON.stringify( outputList, null, 4 );

Это будет log:

[
    {
        "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 и переменной temp:

// 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 ).

Ответ 2

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"}
];

Что именно вы просили?

Ответ 3

Я знаю, что ответов уже много, но лучший из них, который работал для меня для сложной структуры 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);

Ответ 4

Возрождение старого вопроса, но я хотел опубликовать итерацию в ответе @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

Ответ 5

Решение для вашего случая:

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;
}

Ответ 6

Для меня работает следующее:

_.uniq(standardsList, JSON.stringify)

Это, вероятно, будет медленным для очень длинных списков.

Ответ 7

Мне нужно было сделать некоторую деинтуляцию объектов 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);

Ответ 8

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))

Ответ 9

** Следующий метод работает так, как вы хотите. Он фильтрует массив на основе всех значений свойств. **

    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"}] 

Ответ 10

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

Ответ 11

Используйте этот псевдокод

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)

Я выбрал массив образцов, похожий на ваш. Его проще сравнивать объекты, как только вы их набираете. Тогда вам просто нужно сравнить строки.

Ответ 12

Вот короткая однострочная с 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();