Подтвердить что ты не робот

Есть ли реализация словаря в JavaScript?

Как я могу реализовать массив с индексом в JavaScript? Есть что-то вроде словаря в .Net?

4b9b3361

Ответ 1

Технически нет, но вы можете использовать обычный JavaScript-объект, например, словарь:

var a = {"a":"wohoo", 2:"hello2", "d":"hello"};
alert(a["a"]);
alert(a[2]);
alert(a["d"]);

Ответ 2

Джон Ресиг (автор jQuery) недавно опубликовал в словарных словах в javascript.

Его решение - назначить значения словаря как свойства объекта. Код, вставленный дословно из статьи:

// The dictionary lookup object
var dict = {};
// Do a jQuery Ajax request for the text dictionary
$.get( "dict/dict.txt", function( txt ) {
  // Get an array of all the words
  var words = txt.split( "\n" );

  // And add them as properties to the dictionary lookup
  // This will allow for fast lookups later
  for ( var i = 0; i < words.length; i++ ) {
    dict[ words[i] ] = true;
  }

  // The game would start after the dictionary was loaded
  // startGame();
});

// Takes in an array of letters and finds the longest
// possible word at the front of the letters
function findWord( letters ) {
  // Clone the array for manipulation
  var curLetters = letters.slice( 0 ), word = "";

  // Make sure the word is at least 3 letters long
  while ( curLetters.length > 2 ) {
    // Get a word out of the existing letters
    word = curLetters.join("");

    // And see if it in the dictionary
    if ( dict[ word ] ) {
      // If it is, return that word
      return word;
    }

    // Otherwise remove another letter from the end
    curLetters.pop();
  }
}

Ответ 3

Вы можете попробовать buckets, это библиотека структуры данных javascript, которая позволяет вам использовать любой тип объекта в словаре.

Ответ 4

В моем последнем проекте мне было поручено создать клиентское приложение для браузера, которое будет читать 10 тысяч строк данных, а затем группировать и агрегировать данные для отображения в сетках и для построения диаграмм. Целевыми технологиями были HTML 5, CSS 3 и EMCS 5. (современный браузер в июне 2013 года). Поскольку более низкая совместимость с браузером не вызывала беспокойства, внешние библиотеки были ограничены D3 (без JQuery).

Мне нужно было создать модель данных. Я создал один из них в С# и полагался на пользовательские словарные объекты для быстрого доступа к данным, группам и агрегатам. Я не работал в JavaScript за многие годы, поэтому начал искать словарь. Я обнаружил, что JavaScript по-прежнему не имеет истинного родного словаря. Я нашел несколько примеров реализации, но ничего, что действительно соответствовало моему ожиданию. Поэтому я построил один.

Как я уже говорил, я не работал в JavaScript уже много лет. Достижения (или, может быть, просто доступность информации в Интернете) были весьма впечатляющими. Вся моя предыдущая работа была связана с языками на основе классов, поэтому базовый язык прототипа занял некоторое время, чтобы привыкнуть (и мне еще предстоит пройти долгий путь).

Этот проект, как и большинство, должен был состояться до того, как он начался, поэтому я узнал, как я стал делать многие из ошибок newb, которые можно было бы ожидать при переходе от класса на основе прототипа. Созданный словарь был функциональным, но через некоторое время я понял некоторые улучшения, которые я смог сделать, сделав его менее новичком. У проекта закончилось финансирование, прежде чем я успел переработать словарь. О, и моя позиция потеряла финансирование в то же время (удивительно, как это может произойти). Поэтому я решил воссоздать словарь, используя то, что я узнал, и определить, действительно ли словарь действительно улучшает производительность над массивом.

/*
* Dictionary Factory Object
* Holds common object functions. similar to V-Table
* this.New() used to create new dictionary objects
* Uses Object.defineProperties so won't work on older browsers.
* Browser Compatibility (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)
*      Firefox (Gecko) 4.0 (2), Chrome 5, IE 9, Opera 11.60, Safari 5
*/
function Dict() {

    /*
    * Create a new Dictionary
    */
    this.New = function () {
        return new dict();
    };

    /*
    * Return argument f if it is a function otherwise return undefined
    */
    function ensureF(f) {
        if (isFunct(f)) {
            return f;
        }
    }

    function isFunct(f) {
        return (typeof f == "function");
    }

    /*
    * Add a "_" as first character just to be sure valid property name
    */
    function makeKey(k) {
        return "_" + k;
    };

    /*
    * Key Value Pair object - held in array
    */
    function newkvp(key, value) {
        return {
            key: key,
            value: value,
            toString: function () { return this.key; },
            valueOf: function () { return this.key; }
        };
    };

    /*
    * Return the current set of keys. 
    */
    function keys(a) {
        // remove the leading "-" character from the keys
        return a.map(function (e) { return e.key.substr(1); });
        // Alternative: Requires Opera 12 vs. 11.60
        // -- Must pass the internal object instead of the array
        // -- Still need to remove the leading "-" to return user key values
        //    Object.keys(o).map(function (e) { return e.key.substr(1); });
    };

    /*
    * Return the current set of values. 
    */
    function values(a) {
        return a.map(function(e) { return e.value; } );
    };

    /*
    * Return the current set of key value pairs. 
    */
    function kvPs(a) {
        // remove the leading "-" character from the keys
        return a.map(function (e) { return newkvp(e.key.substr(1), e.value); });
    }

    /*
    * Returns true if key exists in the dictionary.
    * k - Key to check (with the leading "_" character) 
    */
    function exists(k, o) {
        return o.hasOwnProperty(k);
    }

    /*
    * Array Map implementation
    */
    function map(a, f) {
        if (!isFunct(f)) { return; }
        return a.map(function (e, i) { return f(e.value, i); });
    }

    /*
    * Array Every implementation
    */
    function every(a, f) {
        if (!isFunct(f)) { return; }
        return a.every(function (e, i) { return f(e.value, i) });
    }

    /*
    * Returns subset of "values" where function "f" returns true for the "value"
    */
    function filter(a, f) {
        if (!isFunct(f)) {return; }
        var ret = a.filter(function (e, i) { return f(e.value, i); });
        // if anything returned by array.filter, then get the "values" from the key value pairs
        if (ret && ret.length > 0) {
            ret = values(ret);
        }
        return ret;
    }

    /*
    * Array Reverse implementation
    */
    function reverse(a, o) {
        a.reverse();
        reindex(a, o, 0);
    }

    /**
    * Randomize array element order in-place.
    * Using Fisher-Yates shuffle algorithm.
    * (Added just because:-)
    */
    function shuffle(a, o) {
        var j, t;
        for (var i = a.length - 1; i > 0; i--) {
            j = Math.floor(Math.random() * (i + 1));
            t = a[i];
            a[i] = a[j];
            a[j] = t;
        }
        reindex(a, o, 0);
        return a;
    }
    /*
    * Array Some implementation
    */
    function some(a, f) {
        if (!isFunct(f)) { return; }
        return a.some(function (e, i) { return f(e.value, i) });
    }

    /*
    * Sort the dictionary. Sorts the array and reindexes the object.
    * a - dictionary array
    * o - dictionary object
    * sf - dictionary default sort function (can be undefined)
    * f - sort method sort function argument (can be undefined)
    */
    function sort(a, o, sf, f) {
        var sf1 = f || sf; // sort function  method used if not undefined
        // if there is a customer sort function, use it
        if (isFunct(sf1)) {
            a.sort(function (e1, e2) { return sf1(e1.value, e2.value); });
        }
        else {
            // sort by key values
            a.sort();
        }
        // reindex - adds O(n) to perf
        reindex(a, o, 0);
        // return sorted values (not entire array)
        // adds O(n) to perf
        return values(a);
    };

    /*
    * forEach iteration of "values"
    *   uses "for" loop to allow exiting iteration when function returns true 
    */
    function forEach(a, f) {
        if (!isFunct(f)) { return; }
        // use for loop to allow exiting early and not iterating all items
        for(var i = 0; i < a.length; i++) {
            if (f(a[i].value, i)) { break; }
        }
    };

    /*
    * forEachR iteration of "values" in reverse order
    *   uses "for" loop to allow exiting iteration when function returns true 
    */
    function forEachR(a, f) {
        if (!isFunct(f)) { return; }
        // use for loop to allow exiting early and not iterating all items
        for (var i = a.length - 1; i > -1; i--) {
            if (f(a[i].value, i)) { break; }
        }
    }

    /*
    * Add a new Key Value Pair, or update the value of an existing key value pair
    */
    function add(key, value, a, o, resort, sf) {
        var k = makeKey(key);
        // Update value if key exists
        if (exists(k, o)) {
            a[o[k]].value = value;
        }
        else {
            // Add a new Key value Pair
            var kvp = newkvp(k, value);
            o[kvp.key] = a.length;
            a.push(kvp);
        }
        // resort if requested
        if (resort) { sort(a, o, sf); }
    };

    /*
    * Removes an existing key value pair and returns the "value" If the key does not exists, returns undefined
    */
    function remove(key, a, o) {
        var k = makeKey(key);
        // return undefined if the key does not exist
        if (!exists(k, o)) { return; }
        // get the array index
        var i = o[k];
        // get the key value pair
        var ret = a[i];
        // remove the array element
        a.splice(i, 1);
        // remove the object property
        delete o[k];
        // reindex the object properties from the remove element to end of the array
        reindex(a, o, i);
        // return the removed value
        return ret.value;
    };

    /*
    * Returns true if key exists in the dictionary.
    * k - Key to check (without the leading "_" character) 
    */
    function keyExists(k, o) {
        return exists(makeKey(k), o);
    };

    /*
    * Returns value assocated with "key". Returns undefined if key not found
    */
    function item(key, a, o) {
        var k = makeKey(key);
        if (exists(k, o)) {
            return a[o[k]].value;
        }
    }

    /*
    * changes index values held by object properties to match the array index location
    * Called after sorting or removing
    */
    function reindex(a, o, i){
        for (var j = i; j < a.length; j++) {
            o[a[j].key] = j;
        }
    }

    /*
    * The "real dictionary"
    */
    function dict() {
        var _a = [];
        var _o = {};
        var _sortF;

        Object.defineProperties(this, {
            "length": { get: function () { return _a.length; }, enumerable: true },
            "keys": { get: function() { return keys(_a); }, enumerable: true },
            "values": { get: function() { return values(_a); }, enumerable: true },
            "keyValuePairs": { get: function() { return kvPs(_a); }, enumerable: true},
            "sortFunction": { get: function() { return _sortF; }, set: function(funct) { _sortF = ensureF(funct); }, enumerable: true }
        });

        // Array Methods - Only modification to not pass the actual array to the callback function
        this.map = function(funct) { return map(_a, funct); };
        this.every = function(funct) { return every(_a, funct); };
        this.filter = function(funct) { return filter(_a, funct); };
        this.reverse = function() { reverse(_a, _o); };
        this.shuffle = function () { return shuffle(_a, _o); };
        this.some = function(funct) { return some(_a, funct); };
        this.sort = function(funct) { return sort(_a, _o, _sortF, funct); };

        // Array Methods - Modified aborts when funct returns true.
        this.forEach = function (funct) { forEach(_a, funct) };

        // forEach in reverse order
        this.forEachRev = function (funct) { forEachR(_a, funct) };

        // Dictionary Methods
        this.addOrUpdate = function(key, value, resort) { return add(key, value, _a, _o, resort, _sortF); };
        this.remove = function(key) { return remove(key, _a, _o); };
        this.exists = function(key) { return keyExists(key, _o); };
        this.item = function(key) { return item(key, _a, _o); };
        this.get = function (index) { if (index > -1 && index < _a.length) { return _a[index].value; } } ,
        this.clear = function() { _a = []; _o = {}; };

        return this;
    }


    return this;
}

Одно из прозрений, которые я испытывал при попытке мысленно примирить объекты класса и прототипа, состоит в том, что прототип в основном представляет собой v-таблицу для созданных объектов. Кроме того, функции в корпусе могут также действовать как записи v-таблицы. По мере продвижения проекта я начал использовать Объектные Объекты, где объект верхнего уровня содержал общие функции для типа объекта и включал метод this.New(args), который использовался для создания реальных объектов, используемых в решении. Это стиль, который я использовал для словаря.

Ядром словаря является объект Array, Object и KeyValuePair. Метод addOrUpdate принимает ключ и значение и:

  • Создает KeyValuePair
  • Добавляет новое свойство к объекту с использованием ключа в качестве имени свойства и длина массива как значение свойства
  • Добавить KeyValuePair в массив, что делает объект новым свойством значение индекса в массиве

ПРИМЕЧАНИЕ.. Я читал, что имена свойств объекта могут начинаться с символа "почти любого" Юникода. Проект будет иметь дело с данными клиента, которые могут начинаться с "любого" символа Юникода. Чтобы словарь не раздувался из-за недопустимого имени свойства, я префикс подчеркивания (_) к ключу и отменил это подчеркивание при возврате ключей, внешних по отношению к словарю.

Для того чтобы словарь функционировал, внутренний массив и объект должны храниться в синхронизации. Чтобы гарантировать, что ни Массив, ни Объект не отображаются снаружи. Я хотел избежать случайных изменений, таких как те, которые могут произойти, когда тест "Если" имеет только один знак равенства, а значение слева установлено по ошибке.

If(dict.KeyObj["SomeKey"] = "oops") { alert("good luck tracing this down:-)"); }

Эта типичная ошибка со словарем может быть очень сложной для отслеживания, когда ошибки (симптомы) начинают отображаться при вычислении, отображении и т.д. Следовательно, свойство "this" не будет иметь доступа ни к одному из них. Этот протекционизм является одной из причин, по которым я больше не копался в прототипах. Мне пришло в голову использовать внутренний объект с объектом Array и Object и передать этот внутренний объект при использовании методов "вызова" или "применить", и я могу взглянуть на это позже, пока я все еще не уверен, что мне не придется выставлять это внутренний объект, который бы превзошел цель защиты основного массива и объекта.

Я исправил некоторые из ошибок newb, которые я сделал с первым созданным объектом словаря.

  • Функция "Dict()" содержит большую часть рабочего кода для каждого словарь. Критерии, которые я использовал для определения того, закрытая функция должна использоваться против функциональности в фактической словарь:
    • Более одной строки кода
    • Используется другими закрытыми функциями
    • Может быть изменен, что приведет к росту, поскольку я обнаруживаю ошибки/проблемы.
  • Используется метод и свойства массива, где это имеет смысл. приход от С# Я делал то, что сделало мой словарь менее полезным для использования "Count" вместо "length" или "ForEach" вместо "forEach". От используя имена Array, словарь теперь можно использовать как массив в большинстве случаев. К сожалению, я не смог найти способ создания скобки accessor (например, val = dict [key]), и это может быть хорошо. Когда я думал об этом, я с трудом мог убедиться, что такие вещи, как val = dict [12] работал правильно. Число 12 легко могло быть использовалось как ключ, поэтому я не мог придумать хороший способ узнать "намерение" такого вызова.
  • Полностью закрыл обработку префикса подчеркивания. В проекте я был Работая, я распространил это и повторил в различных данных модели объекты. Это было некрасиво!

Ответ 5

В JS { "index": anyValue} - это просто словарь. Вы также можете обратиться к определению JSON (http://www.json.org/)

Ответ 6

Ближайшая реализация, которую я использовал в словаре .Net в Javascript, является хеш-объектом (см. ссылку: http://www.mojavelinux.com/articles/javascript_hashes.html). Он реализует массив под капотом и имеет аналогичные методы с именами словаря .Net.

Ответ 7

Используйте объект, как пишут другие люди. Если вы сохраняете что-то другое, кроме строк, как ключ, просто отрисуйте их. См. Это сообщение в блоге для оценки производительности различных реализаций словарей в javascript.

Ответ 8

ECMAScript 6 (аналогично спецификации JavaScript 2015), указывает интерфейс словаря с именем Карта. Он поддерживает произвольные ключи любого типа, имеет свойство size только для чтения, не загроможден связанными с прототипами материалами, подобными объектам, и может быть повторен с использованием новой конструкции for...of... или Map.forEach. Проверьте документацию на MDN здесь, а таблица совместимости браузера здесь.

Ответ 9

var nDictionary = Object.create(null);

function setDictionary(index, value) {
    nDictionary[index] = value;
}

function getDictionary(index) {
    return nDictionary[index];
}

setDictionary(81403, "test 1");
setDictionary(81404, "test 2");
setDictionary(81405, "test 3");
setDictionary(81406, "test 4");
setDictionary(81407, "test 5");

alert(getDictionary(81403));