Предполагая, что у меня есть следующее:
var array =
[
{"name":"Joe", "age":17},
{"name":"Bob", "age":17},
{"name":"Carl", "age": 35}
]
Каков наилучший способ получить массив всех различных возрастов, чтобы я получил массив результатов:
[17, 35]
Есть ли какой-нибудь способ, которым я мог бы альтернативно структурировать данные или лучший метод так, чтобы мне не приходилось бы перебирать каждый массив, проверяя значение «age», проверять другой массив на наличие и добавлять его, если нет?
Если бы был какой-то способ, я мог бы просто вытащить различные эпохи, не повторяя ...
Текущий неэффективный способ я бы хотел улучшить ... Если бы это означало, что вместо «массива» был бы массив объектов, а была бы «карта» объектов с некоторым уникальным ключом (то есть «1,2,3»), который был бы тоже хорошо Я просто ищу наиболее эффективный способ.
Вот как я это делаю в настоящее время, но для меня итерация выглядит просто неприлично для эффективности, даже если она работает ...
var distinct = []
for (var i = 0; i < array.length; i++)
if (array[i].age not in distinct)
distinct.push(array[i].age)
источник
Set
объект иmap
s расточительны. Эта работа просто проходит простой.reduce()
этап.Ответы:
Если бы это был PHP, я бы собрал массив с ключами и взял бы
array_keys
в конце, но у JS такой роскоши нет. Вместо этого попробуйте это:источник
array_unique
что сравнил бы весь предмет, а не только возраст, как здесь просят.flags = {}
это лучше, чемflags = []
age
это относительно небольшое целое число (<120, безусловно)Если вы используете ES6 / ES2015 или новее, вы можете сделать это следующим образом:
Вот пример того, как это сделать.
источник
TypeError: (intermediate value).slice is not a function
используя ES6
источник
array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Вы можете использовать словарный подход, как этот. По сути, вы присваиваете значение, которое вы хотите различить, как ключ в «словаре» (здесь мы используем массив как объект, чтобы избежать словарного режима). Если ключ не существует, вы добавляете это значение как отдельное.
Вот рабочая демонстрация:
Это будет O (n), где n - количество объектов в массиве, а m - количество уникальных значений. Нет более быстрого способа, чем O (n), потому что вы должны проверять каждое значение хотя бы один раз.
Предыдущая версия этого использовала объект, и для in. Они были незначительными по своей природе, и с тех пор были незначительно обновлены выше. Однако причина кажущегося повышения производительности между двумя версиями в исходном jsperf была из-за того, что размер выборки данных был настолько мал. Таким образом, основное сравнение в предыдущей версии заключалось в разнице между внутренней картой и использованием фильтра по сравнению с поиском в режиме словаря.
Я обновил приведенный выше код, как уже было отмечено, однако я также обновил jsperf для просмотра 1000 объектов вместо 3. 3 упустил из виду многие подводные камни, связанные с производительностью ( устаревший jsperf ).
Представление
https://jsperf.com/filter-vs-dictionary-more-data Когда я запустил этот словарь, он был на 96% быстрее.
источник
if( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
Вот как вы могли бы решить эту проблему с помощью нового набора через ES6 для Typescript от 25 августа 2017 года
источник
Используя функции ES6, вы можете сделать что-то вроде:
источник
const uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Я бы просто отобразил и удалил дупс:
Редактировать: Aight! Не самый эффективный способ с точки зрения производительности, но самый простой и читаемый IMO. Если вы действительно заботитесь о микрооптимизации или у вас огромные объемы данных, то регулярный
for
цикл будет более «эффективным».источник
if
s. с тремя миллионами вы получите совсем другие результаты.Пример ES6
источник
Для тех, кто хочет вернуть объект со всеми свойствами, уникальными по ключу
источник
Уже есть много правильных ответов, но я хотел добавить тот, который использует только
reduce()
метод, потому что он чистый и простой.Используйте это так:
источник
forEach
Версия ответа @ Travis-J (полезно на современных браузерах и Node JS мира):На 34% быстрее в Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3
И общее решение, которое принимает функцию картографирования (чуть медленнее, чем прямое отображение, но это ожидается):
источник
Я начал использовать Underscore во всех новых проектах по умолчанию, чтобы мне никогда не приходилось думать об этих небольших проблемах с обработкой данных.
Производит
[17, 35]
.источник
Вот еще один способ решить эту проблему:
Я понятия не имею, насколько быстро это решение сравнивается с другими, но мне нравится более чистый внешний вид. ;-)
РЕДАКТИРОВАТЬ: Хорошо, выше, кажется, самое медленное решение из всех здесь.
Я создал тест для тестирования производительности здесь: http://jsperf.com/distinct-values-from-array
Вместо того, чтобы проверять возрасты (целые числа), я решил сравнить имена (строки).
Метод 1 (решение TS) очень быстрый. Интересно, что метод 7 превосходит все другие решения, здесь я только что избавился от .indexOf () и использовал его «ручную» реализацию, избегая вызова зацикленных функций:
Разница в производительности с использованием Safari и Firefox поразительна, и кажется, что Chrome лучше всего справляется с оптимизацией.
Я не совсем уверен, почему вышеупомянутые фрагменты так быстры по сравнению с другими, может быть, кто-то мудрее меня имеет ответ. ;-)
источник
используя lodash
источник
Использование Lodash
Возвращает [17,35]
источник
источник
underscore.js
_.uniq(_.pluck(array,"age"))
источник
Вот универсальное решение, которое использует сокращение, позволяет отображать и поддерживает порядок вставки.
элементы : массив
mapper : унарная функция, которая отображает элемент в соответствии с критериями, или пустая для сопоставления самого элемента.
Применение
Вы можете добавить это в свой прототип Array и пропустить параметр items, если это ваш стиль ...
Вы также можете использовать Set вместо Array для ускорения сопоставления.
источник
источник
Просто нашел это, и я подумал, что это полезно
Снова используя подчеркивание , так что если у вас есть такой объект
это даст вам только уникальные объекты.
Здесь происходит то, что
indexBy
возвращает такую картуи только потому, что это карта, все ключи уникальны.
Тогда я просто отображаю этот список обратно в массив.
В случае, если вам нужны только отдельные значения
Имейте в виду, что
key
возвращается как строка, поэтому, если вам нужны целые числа, вы должны сделатьисточник
я думаю, что вы ищете функцию groupBy (используя Lodash)
дает результат:
Демонстрация jsFiddle: http://jsfiddle.net/4J2SX/201/
источник
Если, как и я, вы предпочитаете более «функциональный» режим без ущерба для скорости, в этом примере используется быстрый поиск по словарю, заключенный в уменьшить замыкание.
Согласно этому тесту мое решение в два раза быстрее предложенного ответа
источник
источник
Я знаю, что мой код имеет небольшую длину и небольшую сложность по времени, но это понятно, поэтому я попробовал этот путь.
Я пытаюсь разработать функцию на основе прототипа здесь, и код также меняется.
Здесь Distinct - моя собственная функция-прототип.
источник
Если у вас есть Array.prototype.include или вы хотите его заполнить , это работает:
источник
Мой код ниже покажет уникальный массив возрастов, а также новый массив, не имеющий повторяющийся возраст
источник
Я написал свой собственный в TypeScript, для общего случая, например, в Kotlin's
Array.distinctBy {}
...Где
U
это можно, конечно. Для объектов вам может понадобиться https://www.npmjs.com/package/es6-json-stable-stringifyисточник
Если вам нужен уникальный объект
[Объект {x: 1, y: 2}, Объект {x: 2, y: 1}]
источник
Отвечать на этот старый вопрос довольно бессмысленно, но есть простой ответ, который говорит о природе Javascript. Объекты в Javascript по своей сути являются хеш-таблицами. Мы можем использовать это, чтобы получить хеш уникальных ключей:
Затем мы можем уменьшить хеш до массива уникальных значений:
Это все, что вам нужно. Массив a2 содержит только уникальные возрасты.
источник
Простой однострочник с отличными характеристиками. На 6% быстрее, чем решения ES6 в моих тестах .
источник
array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i)
. Теперь я использую ключевое слово function так редко, что мне приходится дважды что-то читать, когда я его вижу 😊