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

Цікаво, чи є лодаш ярлик.

Відповіді:


134

Інший спосіб з лодашем 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 the _.keyByперетворить весь масив на об'єкт, тоді як питання в основному полягає в тому, щоб мати один елемент від кожного об'єкта в масиві як ключ, а один інший елемент як його значення. Якщо _.keyByвикористовується, тоді всі значення будуть об'єктами.
Мустафа Ехсан Алокозай

Дякую @MustafaEhsanAlokozay Ви маєте рацію, ця відповідь не робить точно правильної речі. Я видалю свій коментар, оскільки це не корисно. Це може зробити ваш коментар дивним, але краще, ніж, якщо мій неправильний коментар залишиться на місці довше.
Акрікос

54

Ви повинні використовувати _.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
Спочатку подивіться на це, щоб зрозуміти найбільш голосовану відповідь stasovlas.
Роман Сусі

3
Це крута відповідь, але вона НЕ відповідає на питання. Значення повинні бути рядками, а не об'єктами.
Дем Пілафіян,

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якщо це точно не виражає того, що ви намагаєтесь зробити: це значно затемнює точку коду в будь-якому іншому випадку. Я особисто віддаю перевагу _.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.
Ben Steward


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-yuri

6

Інший спосіб з лодашем

створення пар, а потім або побудувати об’єкт, або 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.