Преобразование массива объектов в хэш-карту с использованием lodash

Вариант использования состоит в том, чтобы преобразовать массив объектов в хэш-карту, где одно свойство является ключом, а другое свойство - значением. Частым случаем использования этого является преобразование объекта «link» в гипермедийный ответ в хэш-карту ссылок.

jsfiddle

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.

60 голосов | спросил Pete 22 J000000Tuesday14 2014, 00:01:42

7 ответов


79

Я думаю, что вы ищете _.keyBy (или _.indexBy в старых версиях)

_.keyBy(data, 'rel');
ответил Jon Anderson 22 J000000Tuesday14 2014, 00:14:25
36

Пересмотренное решение

В соответствии с замечанием Pau Fracé выше, вот полное решение. Решение, данное Джоном Андерсоном, будет индексировать все объекты ключом. Однако это не создало бы пару пар ключ-значение.

Чтобы завершить решение создания полного хеш-карты, значения должны быть сопоставлены с ключом. Используя функцию transform , значения могут быть извлечены из объектов и отображены обратно на ключ или в этом случае rel

Псевдокод

  1. Индексировать все объекты по выбранному ключу.
  2. Сопоставьте все значения с ключом.

код

Ниже приведен полный код с включенным протоколированием. Для версии без регистрации удалите все строки с помощью функции 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>
ответил Pete 13 MarpmFri, 13 Mar 2015 21:13:05 +03002015-03-13T21:13:05+03:0009 2015, 21:13:05
14

В ES7 это теперь просто:

data.reduce((acc, { rel, href }) => ({ ...acc, [rel]: href }), {});

(даже не используя Lodash).

ответил hon2a 24 MarpmThu, 24 Mar 2016 13:38:13 +03002016-03-24T13:38:13+03:0001 2016, 13:38:13
9

Проще было бы использовать «уменьшить».

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 как значением.

ответил Matt 14 MarpmMon, 14 Mar 2016 14:03:27 +03002016-03-14T14:03:27+03:0002 2016, 14:03:27
6

Так как 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];
}));
ответил Ricardo Stuven 25 Maypm16 2016, 17:05:22
2

С Lodash 4:

Использование keyBy и mapValues

_.mapValues(_.keyBy(data, 'rel'), v => v.href);

Или:

_.chain(data).keyBy('rel').mapValues(v => v.href).value();
ответил rocketspacer 16 MarpmThu, 16 Mar 2017 21:18:51 +03002017-03-16T21:18:51+03:0009 2017, 21:18:51
0

Я уже вижу много хороших ответов. Я просто хотел бы добавить еще один ответ в список, используя 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>

Надеюсь, это поможет кому-то еще:)

ответил Abhishek Ghosh 15 Jpm1000000pmMon, 15 Jan 2018 23:02:53 +030018 2018, 23:02:53

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132