lodash: отображение массива на объект

91

Есть ли встроенная функция lodash для этого:

var params = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];

И выведите это:

var output = {
    foo: 'bar',
    baz: 'zle'
};

Сейчас я просто использую Array.prototype.reduce():

function toHash(array, keyName, valueName) {
    return array.reduce(function(dictionary, next) {
        dictionary[next[keyName]] = next[valueName];
        return dictionary;
    }, {});
}

toHash(params, 'name', 'input');

Интересно, есть ли короткий путь к lodash.

ядро
источник

Ответы:

133

Другой способ с lodash 4.17.2

_.chain(params)
    .keyBy('name')
    .mapValues('input')
    .value();

или

_.mapValues(_.keyBy(params, 'name'), 'input')

или с _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)
Стасовлас
источник
@Akrikos _.keyByпреобразует весь массив в объект, тогда как вопрос в основном заключается в том, чтобы иметь один элемент из каждого объекта в массиве в качестве ключа и еще один элемент в качестве его значения. Если _.keyByиспользуется, то все значения будут объектами.
Мустафа Эхсан
Спасибо @MustafaEhsanAlokozay. Вы правы, этот ответ не совсем правильный. Я удалю свой комментарий, так как он бесполезен. Это может сделать ваш комментарий странным, но лучше, чем если бы мой неправильный комментарий не ложился дольше.
Акрикос,
53

Вы должны использовать _.keyBy, чтобы легко преобразовать массив в объект.

Документы здесь

Пример использования ниже:

var params = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];
console.log(_.keyBy(params, 'name'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

При необходимости вы можете манипулировать массивом перед использованием _.keyBy или объектом после использования _.keyBy, чтобы получить точный желаемый результат.

danday74
источник
2
Сначала посмотрите на это, чтобы понять, какой ответ Стасовла получил наибольшее количество голосов.
Роман Суси
3
Это крутой ответ, но он НЕ отвечает на вопрос. Значения должны быть строками, а не объектами.
Dem
34

Да, это здесь , используя_.reduce

var params = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];

_.reduce(params , function(obj,param) {
 obj[param.name] = param.input
 return obj;
}, {});
Джагдиш Идхате
источник
И снова reduce()появляется другой вариант использования. Умный способ сделать это!
Дэн
У кого-нибудь есть машинописная версия этого?
mr.bjerre
Реальность такова, что математически верно то, что вы можете реализовать буквально любое действие итерации с помощью reduce / inject, поскольку сокращение изоморфно списку. Однако за такую ​​гибкость приходится расплачиваться удобочитаемостью. Не используйте, _.reduceесли это точно не выражает то, что вы пытаетесь сделать: это значительно затемняет смысл кода в любом другом случае. Я лично предпочитаю _.zipObjectрешение @djechlin - в противном случае подход _.keyBy/ _.mapValues.
Роберт Фишер
16

Это похоже на работу для Object.assign:

const output = Object.assign({}, ...params.map(p => ({[p.name]: p.input})));

Отредактировано так, чтобы обернуть как функцию, аналогичную OP, это будет:

const toHash = (array, keyName, valueName) => 
    Object.assign({}, ...array.map(o => ({[o[keyName]]: o[valueName]})));

(Спасибо Бену Стюарду, хорошие мысли ...)

ДождьКолония
источник
Возможно, оберните это в родительскую функцию, чтобы пользователь мог определить, какие ключи будут использоваться, передав их, как это сделал OP.
Бен Стюард
11

Вы можете использовать один лайнер javascript с методом уменьшения массива и деструктуризацией ES6 для преобразования массива пар ключ-значение в объект.

arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});
Фейсал Хаснайн
источник
3
К сожалению, это O (n ^ 2).
jimrandomh
10

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

Моя рекомендация, zipObjectэто довольно логично:

_.zipObject(_.map(params, 'name'), _.map(params, 'input'));

Другой вариант, более хитрый, с использованием fromPairs:

_.fromPairs(_.map(params, function(val) { return [val['name'], val['input']));

Анонимная функция показывает хакерство - я не верю, что JS гарантирует порядок элементов в итерации объекта, поэтому вызов .values()не подходит .

Джехлин
источник
Я не вижу ничего хитрого в использовании fromPairs, да и звонки values()действительно не годятся. По крайней мере, с точки зрения удобочитаемости.
x-
6

Другой способ с lodash

создание пар, а затем либо построить объект, либо ES6 Mapлегко

_(params).map(v=>[v.name, v.input]).fromPairs().value()

или

_.fromPairs(params.map(v=>[v.name, v.input]))

Вот рабочий пример

Кушик Чаттерджи
источник
1
Хорошая часть этого решения заключается в том, что оно также возможно в обычном ES:Object.fromEntries(params.map(v => [v.name, v.input]))
fregante
@fregante, Chrome 73+ только caniuse.com/?search=fromEntries
d9k
6

Его также можно решить без использования какой-либо функции lodash, например:

let paramsVal = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];
let output = {};

paramsVal.forEach(({name, input})=>{
  output[name] = input;
})


console.log(output);

введите описание изображения здесь

Зишан Афзал Сатти
источник