Как я могу реализовать массив с индексом в JavaScript? Есть что-то вроде словаря в .Net?
Есть ли реализация словаря в JavaScript?
Ответ 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));