Що таке 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.