Новый ES 6 (Гармония) представляет новый объект Set . Алгоритм идентификации, используемый Set, похож на ===
оператор и поэтому мало подходит для сравнения объектов:
var set = new Set();
set.add({a:1});
set.add({a:1});
console.log([...set.values()]); // Array [ Object, Object ]
Как настроить равенство для объектов Set для глубокого сравнения объектов? Есть что-нибудь похожее на Java equals(Object)
?
===
оператор. Установленный объект ES6 не имеет методов сравнения..has()
Метод и.add()
методы работа только с нее быть тем же самым реальным объектом или же значением для примитивного.Ответы:
Объект ES6
Set
не имеет методов сравнения или настраиваемой расширяемости сравнения.В
.has()
,.add()
и.delete()
методы работы только от него быть таким же реальным объектом или же значением для примитивного и не имеют средств для подключения к или заменить только что логика.Вы могли бы предположительно получить свой собственный объект из a
Set
и replace.has()
,.add()
а.delete()
методы - с чем-то, что сначала делало глубокое сравнение объектов, чтобы выяснить, есть ли уже элемент в наборе, но производительность, вероятно, не будет хорошей, так как базовыйSet
объект не поможет вообще. Вероятно, вам придется просто выполнить итерацию методом грубой силы по всем существующим объектам, чтобы найти соответствие, используя собственное сравнение, прежде чем вызывать оригинал.add()
.Вот некоторая информация из этой статьи и обсуждение возможностей ES6:
источник
Set
или нет?Как упоминалось в ответе jfriend00, настройка отношения равенства, вероятно, невозможна .
Следующий код представляет схему вычислительно эффективного (но дорогостоящего) обходного пути :
Каждый вставленный элемент должен реализовывать
toIdString()
метод, который возвращает строку. Два объекта считаются равными тогда и только тогда, когда ихtoIdString
методы возвращают одно и то же значение.источник
item.toIdString()
является инвариантным и не может измениться. Потому что, если это возможно, то онGeneralSet
может легко стать недействительным с «дублирующимися» элементами в нем. Таким образом, подобное решение будет ограничено только некоторыми ситуациями, в которых сами объекты не изменяются при использовании набора или когда набор, который становится недействительным, не имеет значения. Все эти проблемы, вероятно, дополнительно объясняют, почему ES6 Set не предоставляет эту функциональность, потому что он действительно работает только при определенных обстоятельствах..delete()
этого ответа?Как отмечается в верхнем ответе , настройка равенства проблематична для изменчивых объектов. Хорошая новость (и я удивлен, что никто еще не упомянул об этом) есть очень популярная библиотека под названием immutable-js, которая предоставляет богатый набор неизменяемых типов, которые обеспечивают семантику глубокого равенства равенства, которую вы ищете.
Вот ваш пример использования immutable-js :
источник
Чтобы добавить здесь ответы, я пошел дальше и реализовал оболочку Map, которая принимает пользовательскую хеш-функцию, пользовательскую функцию равенства и хранит различные значения, которые имеют эквивалентные (пользовательские) хеши в контейнерах.
Как и ожидалось, он оказался медленнее, чем метод конкатенации строк czerny .
Полный источник здесь: https://github.com/makoConstruct/ValueMap
источник
Point
определенное как,{ x: number, y: number }
то,id string
вероятно, вашx.toString() + ',' + y.toString()
.String
, тогда вы можете пропустить весь шаг хеширования и сегментирования, как вы сказали, и просто напрямую использоватьMap
или даже простой объект старого стиля в терминах производного ключа.{x: '1,2', y: '3'}
и{x: '1', y: '2,3'}
, тоString(x) + ',' + String(y)
выведите одинаковое значение для обоих объектов. Более безопасный вариант, при условии, что вы можете рассчитывать наJSON.stringify()
детерминированность, состоит в том, чтобы использоватьJSON.stringify([x, y])
вместо него экранирование и использование строки .Сравнивать их напрямую кажется невозможным, но JSON.stringify работает, если ключи были отсортированы. Как я указал в комментарии
JSON.stringify ({a: 1, b: 2})! == JSON.stringify ({b: 2, a: 1});
Но мы можем обойти это с помощью специального метода stringify. Сначала мы пишем метод
Custom Stringify
Набор
Теперь мы используем набор. Но мы используем набор строк вместо объектов
Получить все значения
После того, как мы создали набор и добавили значения, мы можем получить все значения
Вот ссылка со всеми в одном файле http://tpcg.io/FnJg2i
источник
Может быть, вы можете попробовать использовать
JSON.stringify()
для глубокого сравнения объектов.например :
источник
Для пользователей Typescript ответы других (особенно czerny ) можно обобщить в хороший типобезопасный и многократно используемый базовый класс:
В этом случае реализация примера так проста: просто переопределите
stringifyKey
метод. В моем случае я даю некотороеuri
свойство.Пример использования тогда, как если бы это было обычным
Map<K, V>
.источник
Создайте новый набор из комбинации обоих наборов, затем сравните длину.
set1 равно set2 = true
set1 равно set4 = false
источник
Для того, кто нашел этот вопрос в Google (как я) и хотел получить значение карты, используя объект в качестве ключа:
Предупреждение: этот ответ не будет работать со всеми объектами
Вывод:
источник