Объекты против массивов в JavaScript для пар ключ/значение


скажем, у вас очень простая структура данных:

(personId, name)

...и вы хотите сохранить ряд из них в переменной javascript. Как я вижу у вас есть три варианта:

// a single object
var people = {
    1 : 'Joe',
    3 : 'Sam',
    8 : 'Eve'
};

// or, an array of objects
var people = [
    { id: 1, name: 'Joe'},
    { id: 3, name: 'Sam'},
    { id: 8, name: 'Eve'}
];

// or, a combination of the two
var people = {
    1 : { id: 1, name: 'Joe'},
    3 : { id: 3, name: 'Sam'},
    8 : { id: 8, name: 'Eve'}
};

второй или третий вариант-это, очевидно, путь, если у вас есть (или ожидаете, что у вас может быть) более одной части "значения" для хранения (например, добавление в их возрасте или что-то еще), поэтому, ради аргумента, давайте предположим, что никогда больше не будет никаких значений данных, необходимых в эта структура. Какой из них вы выберете и почему?


Edit: пример теперь показывает наиболее распространенную ситуацию: не последовательные идентификаторы.

6 77

6 ответов:

каждое решение имеет свои варианты использования.

Я думаю, что первое решение хорошо, если вы пытаетесь определить отношение "один к одному" (например, простое сопоставление), особенно если вам нужно использовать ключ в качестве ключа поиска.

второе решение кажется мне самым надежным в целом, и я бы, вероятно, использовал его, если бы мне не нужен был быстрый ключ поиска:

  • это самоописание, так что вам не должны зависеть от тех, кто использует человек чтобы знать, что ключ-это идентификатор пользователя.
  • каждый объект самодостаточный, что лучше для передачи данных в другом месте - вместо двух параметров (id и имя) вы просто проходите вокруг люди.
  • это редкая проблема, но иногда значения ключа могут быть недопустимы для использовать в качестве ключей. Например, я однажды требуется сопоставить преобразования строк (например,": "to">"), но поскольку ":" не является ли допустимым именем переменной, которое я должен был используйте второй способ.
  • он легко расширяется, в случай где-то вдоль линии вы должны добавьте дополнительные данные для некоторых (или всех) пользователей. (Извините, я знаю о вашем "for аргумент" но это важный аспект.)

третье было бы хорошо, если вам нужно быстрое время поиска + некоторые из преимуществ, перечисленных выше (передача данных вокруг, самоописание). Однако, если вам не нужно быстрое время поиска, это намного сложнее. Кроме того, в любом случае вы рискуете ошибиться, если идентификатор в объекте каким-то образом отличается от id в человек.

на самом деле, есть четвертый вариант:

var people = ['Joe', 'Sam', 'Eve'];

так как ваши значения оказываются последовательными. (Конечно, вам придется добавить/вычесть один --- или просто поставить undefined в качестве первого элемента).

лично я бы пошел с вашим (1) или (3), потому что они будут быстрее всего искать кого-то по ID (O logn в худшем случае). Если вам нужно найти id 3 в (2), Вы можете либо найти его по индексу (в этом случае мой (4) в порядке), либо вам нужно выполнить поиск - O (n).

уточнение: я говорю O (logn) это худшее, что может быть, потому что, AFAIK, и реализация может решить использовать сбалансированное дерево вместо хэш-таблицы. Хэш-таблица будет O (1), предполагая минимальные коллизии.

Edit from nickf: с тех пор я изменил пример в OP, поэтому этот ответ может больше не иметь смысла. Извинения.

редактировать

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

Вариант (1) был бы полезен, если (А) вам нужно сохранить память; (б) вам никогда не нужно переходить от объекта обратно к идентификатору; (в) вы никогда не будете расширять сохраненные данные (например, вы не можете добавить фамилию человека)

Вариант (2) хорош, если вам (а) нужно сохранить порядок; (Б) нужно перебирать все элементы; (в) не нужно для поиска элементов по id, если он не отсортирован по id (вы можете выполнить двоичный поиск в O (logn). Обратите внимание, конечно, если вам нужно сохранить его сортировку, то вы будете платить стоимость на insert.

предполагая, что данные никогда не изменятся, первый (единственный объект) вариант является лучшим.

Я создал небольшую библиотеку для управления пар ключ / значение.

https://github.com/scaraveos/keyval.js#readme

Он использует

  • объект для хранения ключей, который позволяет быстро удалять и извлекать значения операции и
  • связанный список, чтобы обеспечить действительно быстрое значение итерации

надеюсь, что это помогает :)

третий вариант является лучшим для любого перспективного приложения. Вероятно, вы захотите добавить больше полей в свою личную запись, поэтому первый вариант непригоден. Кроме того, очень вероятно, что у вас будет большое количество людей для хранения, и вы захотите быстро искать записи - таким образом, сбрасывать их в простой массив (как это делается в Варианте № 2) тоже не очень хорошая идея.

третий шаблон дает вам возможность использовать любую строку в качестве идентификатора, имеют сложный человек структуры и получить и установить записи человека в постоянное время. Это определенно правильный путь.

одна вещь, которой не хватает варианту № 3, - это стабильный детерминированный порядок (что является преимуществом варианта № 2). Если вам это нужно, я бы рекомендовал сохранить упорядоченный массив идентификаторов лиц в качестве отдельной структуры, когда вам нужно перечислить людей по порядку. Преимущество будет заключаться в том, что вы можете хранить несколько таких массивов для разных порядков одного и того же набора данных.

учитывая ваше ограничение, что вы будете иметь только имя в качестве значения, я бы выбрал первый вариант. Это самый чистый, имеет наименьшие накладные расходы и самый быстрый взгляд вверх.