Що таке JavaScript, еквівалентний C # HashSet?


79

У мене є список з декількох тисяч цілочисельних ключів. Єдине, що мені потрібно зробити із цим списком, це сказати, чи є в списку дане значення чи ні.

Для C # я б використовував a, HashSetщоб зробити цей пошук швидким. Що таке еквівалент JavaScript?


Мінімальний рівень підтримки: IE 9+, jQuery (поточний)


10
Як правило, об'єкт.
pswg


Я погоджуюсь, що це дублікат (хоча не всі беруть участь у використанні карти як набору ..), але відповіді у зв’язаному запитанні пропускають багато ідіосинкразій та приміток, наведених нижче.
user2864740

6
Не дублікат - HashSet і Dictionary є дуже різними. Словник дозволить вам отримати об’єкт. Набір HashSet не дозволяє отримати об’єкт, а лише повідомляє, чи є він там.
Kees C. Bakker

3
Як так, що буквально жодна з цих відповідей не пропускає одного з основних пунктів HashSet <T>? Він дозволяє лише унікальні предмети.
user9993

Відповіді:


81

Під капотом об’єкт JavaScript реалізований за допомогою хеш-таблиці. Отже, ваша Key:Valueпара буде(your integer):true

Функція постійного пошуку може бути реалізована як:

var hash = {
  1:true,
  2:true,
  7:true
  //etc...
};

var checkValue = function(value){
  return hash[value] === true;
};


checkValue(7); // => true
checkValue(3); // => false

4
Приємно. Ще одна річ, на яку слід звернути увагу, якщо ви хочете зробити для ітерації (число в хеші) , num (зберігається як ключ) тут має тип рядка.
Ронгсір

також (значення в хеші) було б достатньо, щоб просто зареєструвати властивість з нульовим значенням - навіть не справжнє булеве значення і видалити за допомогою видалення хешу [значення]
Demetris Leptos

3
У javascript є об’єкт Set, який краще відповідає потребам цієї людини.
ремідіб

4
Специфікація ECMAScript чітко визначає функцію Set.has () як ітерацію по всьому набору, доки не буде знайдено збіг. Здається, це не відповідає заявленій меті OP швидкого пошуку, як HashSet, іншими мовами.
JD Sandifer

4
@JDSandifer: у цій самій специфікації також зазначено: "Об'єкти набору повинні бути реалізовані з використанням або хеш-таблиць, або інших механізмів, які в середньому забезпечують час доступу, який є підлінійним щодо кількості елементів у колекції. специфікація призначена лише для опису необхідної спостережуваної семантики об’єктів Set. Вона не призначена як життєздатна модель реалізації. " У сучасній JavaScript, Setі Mapкращі речі , щоб використовувати , коли вам необхідний набір або карту.
jmrk

103

Насправді JavaScript надає об'єкт Set , досить простий у використанні:

var set = new Set();
set.add(1);
set.add(2);

set.has(1)    // true

На жаль, він не сумісний з IE9.


15
Це повинна бути найкраща відповідь у 2018 році.
Андерс Торнблад,

1
@LexJacobs: прочитайте вступ до Набору об'єктів у цій специфікації. Реалізації повинні мати швидший пошук ніж O (n), на практиці це означає O (log n) або O (1).
jmrk

Де я можу знайти його реалізацію, і це дерево HashSet чи AVL?
Вояджер

35

Використовуйте предмет. Щоб додати ключ до набору, зробіть:

object[key] = true;

Щоб перевірити, чи є в наборі ключ, виконайте:

if (object.hasOwnProperty(key)) { ... }

Щоб вилучити ключ із набору, зробіть:

delete object[key]

2
unset? Оператор deleteу JS!
gsnedders

Дякую, я збирався перевірити синтаксис
Бармар,

3
Правильний спосіб перевірити наявність ключа в наборі - використовувати object.hasOwnProperty(key). В іншому випадку "toString" in object == true.
Барт,

5
hasOwnProperty працює повільно, а що, якщо є ключ із назвою hasOwnProperty? використовувати o = Object.create (null); щоб створити "хеш-хет" замість літералу, а потім ви можете скористатися швидким доступом до властивості, щоб перевірити наявність ключів замість методичного hasOwnProperty () і не турбуватися про будь-які колізійні властивості при цьому.
dandavis

8

Ви можете використовувати лише звичайний об’єкт JavaScript та ключове слово 'in', щоб побачити, чи має цей об'єкт певний ключ.

var myObj = {
  name: true,
  age: true
}

'name' in myObj //returns true;
'height' in myObj // returns false;

Або якщо ви знаєте, що у вашому об’єкті будуть ключі, які можуть бути вбудовані у властивості об’єкта JavaScript, використовуйте ...

var myObj = {
  name: true,
  age: true
}

myObj.hasOwnProperty('name') //returns true;
myObj.hasOwnProperty('height') // returns false;

'toString' у myObj // повертає true
Barmar

2
а що, якщо є ключ із назвою "hasOwnProperty"?
dandavis

24
Потім ви переоцінюєте своє життя.
Тайлер Макгінніс

@TylerMcGinnis lol - я думаю, це все одно спрацює - але так, переоцініть, чому у вас є властивість під назвою hasOwnProperty .. і просто використовуйте "in" у будь-якому випадку
Demetris Leptos

1
ми, мабуть, забули, що випадок, коли об’єкт є ключем, не розглядається .. якщо ви не ідентифікуєте всі свої об’єкти поступово з «$ id» (я натхненний newtonsoft) або «__ id __», щоб ви могли тоді використовувати це як ключ, будучи об'єктом .. хеш [isNotPrimitive (ключ)? key ['$ id']: key]
Demetris Leptos,

1

Я прочитав рішення і спробував деякі. Спробувавши використати object[key]метод, я зрозумів, що він не спрацює. Я хотів HashSet, який міг би зберігати елементи HTML. При додаванні цих об'єктів keyбуло переведено в рядок, тому я придумав власний набір на основі jQuery. Він підтримує add, remove, containsі clear.

var HashSet = function () {

    var set = [];

    this.add = function (obj) {
        if (!this.contains(obj)) {
            set.push(obj);
        }
    };

    this.remove = function (obj) {
        set = jQuery.grep(set, function (value) {
            return value !== obj;
        });
    };

    this.clear = function () {
        set = [];
    };

    this.contains = function (obj) {
        return $.inArray(obj, set) > -1;
    };

    this.isEmpty = function () {
        return set.length === 0;
    };
};

Примітка.
Додаючи щось на зразок $('#myElement')набору, слід додати справжній елемент HTML $('#myElement')[0]. О ... і якщо ви хочете зберегти список змінених елементів керування - використовуйте ім'я елемента (дав мені проблему з :radioелементами управління).

Примітка 2.
Я думаю, що object[key]для цілих чисел це може бути швидше.

Примітка 3.
Якщо ви збираєтеся зберігати лише номери або рядок, цей набір буде швидшим:

var HashSet = function () {

    var set = {};

    this.add = function (key) {
        set[key] = true;
    };

    this.remove = function (key) {
        delete set[key];
    };

    this.clear = function () {
        set = {};
    };

    this.contains = function (key) {
        return set.hasOwnProperty(key);
    };

    this.isEmpty = function () {
        return jQuery.isEmptyObject(set);
    };
};

3
Це насправді зовсім не HashSet ... Він не відповідає жодному з критеріїв, на які можна було б очікувати HashSet
Ендрю Вітакер,

Він не має продуктивності H1 набору HashSet, це правда. Але він імітує функції H # HetSet.
Kees C. Bakker

3
Ні, він імітує інтерфейс ICollection msdn.microsoft.com/en-us/library/92t2ye13%28v=vs.110%29.aspx, який реалізує HashSet. Точкою HashSet, як правило, буде час пошуку O (1), тоді як перша реалізація, яку ви надаєте, більш схожа за поведінкою до Списку, будучи O (N).
Оскар Берггрен

1
@OskarBerggren - Набір, наданий у Note3, не повинен мати з цим проблем і повинен бути O1.
Kees C. Bakker

1

Карта або якщо немає необхідності повторювати WeakMap

let m1=new Map();

m1.set('isClosed',false);
m1.set('isInitialized',false);

m1.set('isClosed',true);

m1.forEach(function(v,k)
{
    console.log(`${k}=${v}`);
});

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.