lodash: ánh xạ mảng tới đối tượng


91

Có một chức năng lodash tích hợp để thực hiện điều này:

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

Và xuất ra cái này:

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

Hiện tại tôi chỉ đang sử dụng 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');

Tự hỏi nếu có một đường tắt của nhà nghỉ.

Câu trả lời:


135

Một cách khác với lodash 4.17.2

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

hoặc là

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

Hoặc với _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)

@Akrikos _.keyBysẽ chuyển đổi toàn bộ mảng thành một đối tượng, trong khi câu hỏi chủ yếu là về việc có một mục từ mỗi đối tượng trong mảng làm khóa và một mục khác làm giá trị của nó. Nếu _.keyByđược sử dụng, thì tất cả các giá trị sẽ là đối tượng.
Mustafa Ehsan Alokozay

Cảm ơn @MustafaEhsanAlokozay Bạn nói đúng, câu trả lời đó không làm đúng chính xác. Tôi sẽ xóa bình luận của mình vì nó không hữu ích. Điều đó có thể làm cho bình luận của bạn trông kỳ lạ, nhưng tốt hơn là để bình luận không chính xác của tôi ở lại lâu hơn.
Akrikos

54

Bạn nên sử dụng _.keyBy để dễ dàng chuyển đổi một mảng thành một đối tượng.

Tài liệu ở đây

Ví dụ sử dụng bên dưới:

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>

Nếu được yêu cầu, bạn có thể thao tác mảng trước khi sử dụng _.keyBy hoặc đối tượng sau khi sử dụng _.keyBy để nhận được kết quả mong muốn chính xác.


2
Đầu tiên hãy nhìn vào phần này để hiểu câu trả lời được bình chọn nhiều nhất bởi stasovlas.
Roman Susi

3
Đây là một câu trả lời thú vị, nhưng nó KHÔNG trả lời câu hỏi. Các giá trị phải là chuỗi không phải là đối tượng.
Dem Pilafian

34

Đúng, nó ở đây , sử dụng_.reduce

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

_.reduce(params , function(obj,param) {
 obj[param.name] = param.input
 return obj;
}, {});

Tuy nhiên, một lần nữa lại reduce()say mê với một trường hợp sử dụng khác. Cách làm thông minh!
Dan

Có ai có phiên bản đã đánh máy của cái này không?
mr.bjerre

Thực tế là nó đúng về mặt toán học rằng bạn có thể thực hiện bất kỳ hành động lặp lại theo nghĩa đen nào bằng cách sử dụng giảm / tiêm, vì giảm là đẳng cấu cho một danh sách. Tuy nhiên, sự linh hoạt đó đi kèm với một mức giá dễ đọc. Không sử dụng _.reducetrừ khi điều đó thể hiện chính xác những gì bạn đang cố gắng làm: nó che khuất đáng kể điểm của mã trong bất kỳ trường hợp nào khác. Cá nhân tôi thích _.zipObjectgiải pháp của @djechlin - thất bại đó, cách tiếp cận _.keyBy/ _.mapValues.
Robert Fischer

16

Đây có vẻ như là một công việc cho Object.assign:

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

Được chỉnh sửa để bọc thành một hàm tương tự như hàm OP, đây sẽ là:

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

(Cảm ơn Ben Steward, tư duy tốt ...)


Có thể bọc nó trong một hàm cha để người dùng có thể xác định những phím nào sẽ được sử dụng bằng cách chuyển chúng, giống như OP đã có.
Ben Steward,


10

Điều này có lẽ dài dòng hơn bạn muốn, nhưng bạn đang yêu cầu một hoạt động hơi phức tạp để mã thực tế có thể liên quan (kinh dị).

Đề xuất của tôi, với zipObjectđiều đó khá hợp lý:

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

Một tùy chọn khác, hacky hơn, sử dụng fromPairs:

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

Hàm ẩn danh cho thấy sự khó tin - Tôi không tin rằng JS đảm bảo thứ tự của các phần tử trong việc lặp lại đối tượng, vì vậy việc tính toán .values()sẽ không thực hiện được.


Tôi không thấy bất cứ điều gì khó hiểu khi sử dụng fromPairsvalues()thực sự thì việc gọi điện sẽ không thực hiện được. Ít nhất là từ quan điểm dễ đọc.
x-yuri

6

Một cách khác với lodash

tạo các cặp và sau đó tạo một đối tượng hoặc ES6 Mapdễ dàng

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

hoặc là

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

Đây là một ví dụ hoạt động


1
Phần tốt của giải pháp này là nó cũng khả thi trong ES đơn giản:Object.fromEntries(params.map(v => [v.name, v.input]))
fregante

@fregante, Chrome 73+ only caniuse.com/?search=fromEntries
d9k

6

Nó cũng có thể giải quyết mà không cần sử dụng bất kỳ hàm lodash nào như thế này:

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

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


console.log(output);

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.