#javascript #dictionary #key-value
Вопрос:
Мой случай заключается в том, что мне нужно сохранить уникальный ключ, чтобы отслеживать миллионы моих моделей в Javascript, и сохранить пару ключ-значение на карте.
Существует существующая библиотека uuid, которая сгенерирует для меня строковый ключ, но я боюсь, что мне понадобится целочисленный ключ для достижения оптимальной производительности. Однако, похоже, мне придется самому преобразовать строку uuid в уникальное целое число, что не является тривиальным и также имеет накладные расходы.
Есть ли существенная разница в использовании строки в качестве ключа для карты или целого числа?
Комментарии:
1. Вы измерили производительность? Как вы думаете, почему строковые ключи и целочисленные ключи имеют существенно различную производительность?
2. Единственный раз, когда я знаю, что целые числа быстрее, — это когда вы используете разреженный массив вместо карты. «Существует существующая библиотека uuid, которая сгенерирует для меня строковый ключ…» Если uuid в любом случае произвольны, есть ли какая-либо причина, по которой вы не можете начать с 0 и увеличить 1 для каждого?
3. @Крис Велтон, спасибо тебе. После рассмотрения на самом деле кажется, что нет причин, по которым я не должен начинать с 0 и увеличивать 1 каждый. В этом случае было бы быстрее, если бы я использовал обычный разреженный массив вместо карты?
4. Я приведу вам пример…
Ответ №1:
Вот решение, основанное на нашем разговоре.
Существует много подобных способов сделать это, но главное-сохранить обратный индекс для поиска в самой модели, чтобы каждая модель «знала», где она находится в индексе модели.
Правка: В моем первом примере была ошибка, которая появилась бы, если бы массив стал разреженным из-за сокращения array.length.
Это более продвинутый пример, который избавляется от ошибки и имеет класс dataIndex, отвечающий за индексацию, и в котором модели могут выполнять обратный поиск для нескольких индексов.
class dataIndex {
constructor(indexId) {
this.vec = [];
this.indexId = indexId;
this.indexNext = 0;
}
indexModel(model) {
this.vec[model.lookup[this.indexId] = this.indexNext ] = model;
return this;
}
}
class dataModel {
constructor(data) {
this.data = data;
this.lookup = new Map();
}
static compareData(a, b) {
return (a.data === b.data) ? 0:
(a.data > b.data) ? 1 : -1;
}
}
const modelIndex = new dataIndex('primary');
const sortedIndex = new dataIndex('sorted');
for (let i = 0; i < 10; i ) {
let newModel = new dataModel(Math.random());
modelIndex.indexModel(newModel);
}
const ordered = modelIndex.vec.sort((a, b) => dataModel.compareData(a, b))
ordered.forEach(model => sortedIndex.indexModel(model));
console.log(ordered);
Выход:
[
dataModel {
data: 0.08420389624353097,
lookup: Map(0) { primary: 9, sorted: 0 }
},
dataModel {
data: 0.1528733550120258,
lookup: Map(0) { primary: 7, sorted: 1 }
},
dataModel {
data: 0.28483626134194595,
lookup: Map(0) { primary: 8, sorted: 2 }
},
dataModel {
data: 0.3257986769682104,
lookup: Map(0) { primary: 5, sorted: 3 }
},
dataModel {
data: 0.3409113857134396,
lookup: Map(0) { primary: 3, sorted: 4 }
},
dataModel {
data: 0.3841968173496322,
lookup: Map(0) { primary: 1, sorted: 5 }
},
dataModel {
data: 0.40414714769598237,
lookup: Map(0) { primary: 4, sorted: 6 }
},
dataModel {
data: 0.5817767975980099,
lookup: Map(0) { primary: 0, sorted: 7 }
},
dataModel {
data: 0.8091360598739015,
lookup: Map(0) { primary: 2, sorted: 8 }
},
dataModel {
data: 0.8217632650897493,
lookup: Map(0) { primary: 6, sorted: 9 }
}
]
Комментарии:
1. Спасибо вам за ответ. Мне интересно, это в среднем быстрее или медленнее, чем если бы indexArray был картой, учитывая, что модели также могут быть удалены. Т. Е. может произойти случай, когда revIndex начинается со 100000 и заканчивается 999999 с отверстиями посередине.
2. Когда начинают происходить «дыры», это называется переходом от «плотного» массива к «разреженному». Как правило, разреженные массивы довольно хорошо оптимизированы в большинстве реализаций javascript. (На самом деле он хранит их во многом как объекты с ключами и значениями, но внутри они могут сильно оптимизировать «хэширование» в основном непрерывных целых чисел.) news.qooxdoo.org/…
3. @cr001, чтобы дать вам представление о том, что для создания и индексирования 1000000 случайных чисел в моих ноутбуках требуется 175 мс node.js. Сколько миллионов вы хотите отслеживать сразу?
4. Проблема в том, что на данный момент я не совсем уверен, насколько велика она может быть. Он используется для отслеживания чего-то вроде соединений сокетов, поэтому он зависит от многих факторов, которые сейчас невозможно смоделировать. В Java я был бы почти уверен, что разреженные массивы быстрее, чем карты деревьев в случае целочисленных ключей, однако я не уверен, что это так в Javascript.
5. Ну, я не знаю ничего, что было бы быстрее, и второе преимущество использования массива заключается в том, что он обеспечивает легкую доступность собственных оптимизированных Array.filter и Array.sort, которые могут принимать пользовательские обратные вызовы для фильтрации и сортировки. Поэтому, если у вас 10 миллионов записей и вам нужно удалить самые старые 2 миллиона, у вас есть Array.filter, Array.sort, Array.splice и Array.slice, которые помогут вам.