Преобразование массива объектов в хэш-карту с использованием lodash
Вариант использования состоит в том, чтобы преобразовать массив объектов в хэш-карту, где одно свойство является ключом, а другое свойство - значением. Частым случаем использования этого является преобразование объекта «link» в гипермедийный ответ в хэш-карту ссылок.
function toHashMap(data, name, value) {
return _.zipObject(_.pluck(data, name),
_.pluck(data, value));
}
function toMap(data, name, value) {
return _.reduce(data, function(acc, item) {
acc[item[name]] = item[value];
return acc;
}, {});
}
var data = [
{ rel: 'link1', href: 'url1'},
{ rel: 'link2', href: 'url2'},
{ rel: 'link3', href: 'url3'},
{ rel: 'link4', href: 'url4'},
];
console.log(toHashMap(data, 'rel', 'href'));
console.log(toMap(data, 'rel', 'href'));
toHashMap
выглядит гораздо более читабельным, но менее эффективным. toMap
, кажется, имеет лучшую эффективность за счет удобочитаемости.
Есть ли более элегантное решение - то есть как читаемое, так и эффективное? Я подозреваю, что у Lodash может быть функция, чтобы сделать это уже, но я не нашел ничего подобного после просмотра документации API.
7 ответов
Я думаю, что вы ищете _.keyBy
(или _.indexBy
в старых версиях)
_.keyBy(data, 'rel');
Пересмотренное решение
В соответствии с замечанием Pau Fracé выше, вот полное решение. Решение, данное Джоном Андерсоном, будет индексировать все объекты ключом. Однако это не создало бы пару пар ключ-значение.
Чтобы завершить решение создания полного хеш-карты, значения должны быть сопоставлены с ключом. Используя функцию transform , значения могут быть извлечены из объектов и отображены обратно на ключ или в этом случае rel
Псевдокод
- Индексировать все объекты по выбранному ключу.
- Сопоставьте все значения с ключом.
код
Ниже приведен полный код с включенным протоколированием. Для версии без регистрации удалите все строки с помощью функции tap
.
var data = [{ rel: 'link1', href: 'url1' },
{ rel: 'link2', href: 'url2' },
{ rel: 'link3', href: 'url3' },
{ rel: 'link4', href: 'url4' }];
function log(value) {
document.getElementById("output").innerHTML += JSON.stringify(value, null, 2) + "\n"
}
var hashmap = _.chain(data)
.keyBy('rel')
.tap(log) // Line used just for logging
.mapValues('href')
.tap(log)
.value();
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
<pre id="output"></pre>
В ES7 это теперь просто:
data.reduce((acc, { rel, href }) => ({ ...acc, [rel]: href }), {});
(даже не используя Lodash).
Проще было бы использовать «уменьшить».
var data = [
{ rel: 'link1', href: 'url1'},
{ rel: 'link2', href: 'url2'},
{ rel: 'link3', href: 'url3'},
{ rel: 'link4', href: 'url4'},
];
var hashmap = _.reduce(data, function(hash, value) {
var key = value['rel'];
hash[key] = value['href'];
return hash;
}, {});
JSFiddle: https://jsfiddle.net/6txzzxq2/
С уменьшением вы можете перебирать исходный массив с помощью «аккумулятора» (в данном случае нового объекта). Выше мы определяем хэш атрибутом rel с href как значением.
Так как lodash 4 , вы можете использовать _.fromPairs :
var data = [
{ rel: 'link1', href: 'url1'},
{ rel: 'link2', href: 'url2'},
{ rel: 'link3', href: 'url3'},
{ rel: 'link4', href: 'url4'},
];
var hashmap = _.fromPairs(data.map(function(item) {
return [item.rel, item.href];
}));
С Lodash 4:
Использование keyBy
и mapValues
_.mapValues(_.keyBy(data, 'rel'), v => v.href);
Или:
_.chain(data).keyBy('rel').mapValues(v => v.href).value();
Я уже вижу много хороших ответов. Я просто хотел бы добавить еще один ответ в список, используя indexBy .
const data = [{
id: 1,
foo: 'bar'
},
{
id: 2,
baz: 'lorem'
}
];
const dataById = R.indexBy(R.prop('id'), data);
console.log(dataById)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
Надеюсь, это поможет кому-то еще:)