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, чтобы получить точный желаемый результат.


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.
Бен Стюард


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);

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.