Javascript "Набор" для объектов и массивов - PullRequest
1 голос
/ 17 апреля 2019

Есть ли в Javascript встроенный тип для создания набора объектов данных и массивов?

let set = new Set();
set.add({"language": "ecmascript"});
set.add({"language": "ecmascript"});
set.add({"language": "ecmascript"});
set.add({"language": "ecmascript"});
set.add([1,2,3]);
set.add([1,2,3]);
set.add([1,2,3]);
set.add([1,2,3]);
console.log(set);

Набор, который я использую выше, полезен только для примитивов.

1 Ответ

2 голосов
/ 17 апреля 2019

Набор, который я использую выше, полезен только для примитивов.

Это неверно, он отлично работает для объектов. Проблема состоит в том, что различные объекты с одинаковыми свойствами и значениями свойств не равны, поэтому выполнение set.add({"language": "ecmascript"}); дважды добавляет два неравных объекта в набор (оба с одинаковыми именем и значением свойства).

Если вы добавляете один и тот же объект более одного раза, он не будет добавлен во второй раз:

const set = new Set();
const obj = {"language": "ecmascript"};
set.add(obj);
set.add(obj);
console.log(set.size); // 1

Имеет ли Javascript встроенный тип для ...

Если вы хотите, чтобы объекты с одинаковыми свойствами и значениями рассматривались как равные, то нет. Вам нужно было бы указать операцию сравнения, и в JavaScript нет встроенного Set, который бы позволял вам определять операцию сравнения.

Очевидно, вы можете создать его. В качестве отправной точки, я бы, вероятно, использовал Map, обозначенный именами свойств объекта, отсортированный и превращенный в строку через JSON.stringify. (Хотя это не сработает, если вы хотите использовать символьные ключи как часть определения равенства.) Например, если вы рассматриваете только собственные свойства:

const key = JSON.stringify(Object.getOwnPropertyNames(object).sort());

Значением для записи может быть либо просто массив объектов с теми ключами, по которым вы выполняете линейный поиск, либо секунда Map, заданная каким-то хэшем значений свойств, в зависимости от того, сколько объектов вам нужно справиться ...


В комментариях я спросил:

Вам нужно обрабатывать объекты только с сериализуемыми JSON-значениями?

и вы ответили:

У меня есть несколько объектов, которые уже сериализованы, но есть дубликаты, которые я хотел бы удалить, а затем повторно сериализовать.

Да, вы можете использовать Set для этого, если вы не возражаете против повторной сериализации, или Map, если вы хотите пропустить повторную сериализацию:

const unique = new Map();
for (const source of serializedObjects) {
    const sourceObject = JSON.parse(source); // Or parse from whatever serialization it is
    // Build object adding properties in alpha order for stability
    const keyObj = {};
    for (const key of Object.keys(sourceObject).sort()) {
        keyObj[key] = sourceObject[key];
    }
    // Save it using JSON.stringify, which uses ES2015 property order
    map.set(JSON.stringify(keyObj), source);
}
const uniqueSourceStrings = [...map.values()];

Или для самих десериализованных объектов:

const unique = new Map();
for (const source of serializedObjects) {
    const sourceObject = JSON.parse(source); // Or parse from whatever serialization it is
    // Build object adding properties in alpha order for stability
    const keyObj = {};
    for (const key of Object.keys(sourceObject).sort()) {
        keyObj[key] = sourceObject[key];
    }
    // Save it using JSON.stringify, which uses ES2015 property order
    map.set(JSON.stringify(keyObj), sourceObject); // <=================== changed
}
const uniqueSourceObject = [...map.values()];
//    ^^================================================================== changed
...