Я работаю в JavaScript. Я хотел бы сохранить список уникальных неупорядоченных строковых значений со следующими свойствами:
- быстрый способ спросить «А в списке»?
- быстрый способ сделать «удалить А из списка, если он существует в списке»
- быстрый способ сделать «добавить А в список, если его еще нет».
Что я действительно хочу, так это набор. Какие-нибудь предложения для лучшего способа подражать множеству в JavaScript?
В этом вопросе рекомендуется использовать объект с ключами, хранящими свойства, и для всех значений установлено значение true: это разумный способ?
javascript
Ричард
источник
источник
Ответы:
Если вы программируете в среде с поддержкой ES6 (например, node.js, конкретный браузер с необходимыми вам возможностями ES6 или перенос кода ES6 для своей среды), то вы можете использовать
Set
объект, встроенный в ES6 . Он обладает очень хорошими возможностями и может использоваться как есть в вашей среде.Для многих простых вещей в среде ES5 использование объекта работает очень хорошо. Если
obj
ваш объект иA
является переменной, значение которой вы хотите оперировать в наборе, то вы можете сделать это:Код инициализации:
Вопрос 1: есть
A
в списке:Вопрос 2: Удалить «А» из списка, если он там есть:
Вопрос 3: Добавьте «А» в список, если его там еще не было
Для полноты, проверка на наличие
A
в списке немного безопаснее с этим:из-за потенциального конфликта между встроенными методами и / или свойствами базового объекта, такого как
constructor
свойство.Боковая панель на ES6: Текущая рабочая версия ECMAScript 6 или что-то, называемое ES 2015, имеет встроенный объект Set . Это реализовано сейчас в некоторых браузерах. Поскольку доступность браузера со временем меняется, вы можете просмотреть строку
Set
в этой таблице совместимости ES6, чтобы увидеть текущий статус доступности браузера.Одно из преимуществ встроенного объекта Set заключается в том, что он не приводит все ключи к строке, как это делает объект, поэтому вы можете использовать как 5, так и «5» в качестве отдельных ключей. И вы даже можете использовать объекты непосредственно в наборе без преобразования строки. Вот статья, которая описывает некоторые возможности и документацию MDN для объекта Set.
Теперь я написал polyfill для объекта set ES6, чтобы вы могли начать использовать его сейчас, и он автоматически перейдет к встроенному объекту set, если браузер его поддерживает. Преимущество этого в том, что вы пишете ES6-совместимый код, который будет работать вплоть до IE7. Но есть некоторые недостатки. Интерфейс набора ES6 использует преимущества итераторов ES6, так что вы можете делать что-то вроде этого,
for (item of mySet)
и он будет автоматически выполнять итерацию набора для вас. Но этот тип языковой функции не может быть реализован через polyfill. Вы по-прежнему можете выполнять итерацию набора ES6 без использования новых языковых функций ES6, но, честно говоря, без новых языковых функций это не так удобно, как другой интерфейс набора, который я включаю ниже.Вы можете решить, какой из них лучше для вас, посмотрев на оба. ESF set polyfill находится здесь: https://github.com/jfriend00/ES6-Set .
К вашему сведению, в моем собственном тестировании я заметил, что реализация Firefox v29 Set не полностью соответствует текущей версии спецификации. Например, вы не можете
.add()
связывать вызовы методов так, как описывает спецификация и поддерживает мой polyfill. Вероятно, это вопрос спецификации в движении, так как она еще не завершена.Объекты предварительно созданного набора: если вы хотите, чтобы уже созданный объект имел методы для работы с набором, который можно использовать в любом браузере, вы можете использовать ряд различных предварительно созданных объектов, которые реализуют различные типы наборов. Существует мини-набор, представляющий собой небольшой код, который реализует основы заданного объекта. Он также имеет более функциональный набор объектов и несколько дериваций, включая Словарь (давайте сохраним / получим значение для каждого ключа) и ObjectSet (позволим вам сохранить набор объектов - либо объекты JS, либо объекты DOM, для которых вы либо предоставляете функция, которая генерирует уникальный ключ для каждого или ObjectSet будет генерировать ключ для вас).
Вот копия кода для miniSet (самый актуальный код здесь на github ).
источник
Object.keys(obj)
.Object.keys()
требуется IE9, FF4, Safari 5, Opera 12 или выше. Там в polyfill для старых браузеров здесь .obj.hasOwnProperty(prop)
для проверки членства. ИспользуйтеObject.prototype.hasOwnProperty.call(obj, prop)
вместо этого, который работает, даже если «набор» содержит значение"hasOwnProperty"
.Вы можете создать объект без свойств, таких как
который может действовать как набор и исключает необходимость использования
hasOwnProperty
.источник
set = {}
его наследует все свойства от объекта (напримерtoString
), так что вы должны проверить для полезной нагрузки множества (свойства , которые вы добавили) сhasOwnProperty
вif (A in set)
set[A]=true
операторы для каждого элемента, который вы хотите добавить вместо одного инициализатора?s = Object.create(null);s["thorben"] = true;ss = Object.create(s)
Начиная с ECMAScript 6, структура данных Set является встроенной функцией . Совместимость с версиями node.js можно найти здесь .
источник
in
не работает, потому чтоSet
объекты не имеют своих элементов в качестве свойств, что было бы плохо, потому что наборы могут иметь элементы любого типа, но свойства являются строками. Вы можете использоватьhas
:Set([1,2]).has(1)
В версии ES6 Javascript вы встроили тип для набора ( проверьте совместимость с вашим браузером ).
Чтобы добавить элемент в набор, который вы просто используете
.add()
, он запускаетсяO(1)
и либо добавляет элемент в набор (если он не существует), либо ничего не делает, если он уже существует. Вы можете добавить туда элемент любого типа (массивы, строки, числа)Чтобы проверить количество элементов в наборе, вы можете просто использовать
.size
. Также работает вO(1)
Для удаления элемента из набора используйте
.delete()
. Возвращает true, если значение было (и было удалено), и false, если значение не существовало. Также работает вO(1)
.Чтобы проверить, существует ли элемент в наборе, используйте
.has()
, который возвращает истину, если элемент находится в наборе, и ложь в противном случае. Также работает вO(1)
.В дополнение к методам, которые вы хотели, есть несколько дополнительных:
numbers.clear();
просто удалить все элементы из набораnumbers.forEach(callback);
перебирая значения набора в порядке вставкиnumbers.entries();
создать итератор всех значенийnumbers.keys();
возвращает ключи набора, который совпадает сnumbers.values()
Существует также Weakset, который позволяет добавлять только значения типа объекта.
источник
.add()
прогоны в O (1)? Я заинтригован этим,Я начал реализацию наборов, которая в настоящее время довольно хорошо работает с числами и строками. Основное внимание было уделено разностной операции, поэтому я старался сделать ее максимально эффективной. Форкс и обзоры кода приветствуются!
https://github.com/mcrisc/SetJS
источник
Я только что заметил, что в библиотеке d3.js есть реализация наборов, карт и других структур данных. Я не могу спорить об их эффективности, но, судя по тому, что это популярная библиотека, она должна быть именно тем, что вам нужно.
Документация здесь
Для удобства копирую по ссылке (первые 3 функции представляют интерес)
Создает новый набор. Если указан массив, добавляет данный массив строковых значений в возвращаемый набор.
Возвращает true тогда и только тогда, когда в этом наборе есть запись для указанной строки значения.
Добавляет указанную строку значения в этот набор.
Если набор содержит указанную строку значений, удаляет ее и возвращает true. В противном случае этот метод ничего не делает и возвращает false.
Возвращает массив значений строки в этом наборе. Порядок возвращаемых значений произвольный. Может использоваться как удобный способ вычисления уникальных значений для набора строк. Например:
d3.set (["foo", "bar", "foo", "baz"]). values (); // "foo", "bar", "baz"
Вызывает указанную функцию для каждого значения в этом наборе, передавая значение в качестве аргумента. Этот контекст функции является этим набором. Возвращает неопределенное. Порядок итерации произвольный.
Возвращает true тогда и только тогда, когда этот набор имеет нулевые значения.
Возвращает количество значений в этом наборе.
источник
Да, это разумный способ - это все, чем является объект (ну, в данном случае) - набор ключей / значений с прямым доступом.
Вам нужно проверить, чтобы увидеть, находится ли он уже там, прежде чем добавить его, или если вам просто нужно указать присутствие, «добавление» его снова фактически ничего не меняет, оно просто устанавливает его на объекте снова.
источник