lodash: การแมปอาร์เรย์กับวัตถุ


92

มีฟังก์ชั่น 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');

สงสัยว่าจะมีการลัดวงจร

คำตอบ:


138

อีกวิธีหนึ่งกับ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ถูกใช้ค่าทั้งหมดจะเป็นวัตถุ
Mustafa Ehsan Alokozay

ขอบคุณ @MustafaEhsanAlokozay คุณพูดถูกคำตอบนั้นไม่ได้ทำในสิ่งที่ถูกต้อง ฉันจะลบความคิดเห็นของฉันเพราะมันไม่มีประโยชน์ นั่นอาจทำให้ความคิดเห็นของคุณดูแปลก ๆ แต่ก็ดีกว่าที่ความคิดเห็นที่ไม่ถูกต้องของฉันจะอยู่ได้นานกว่านี้
Akrikos

55

คุณควรใช้ _.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
Roman Susi

5
นี่เป็นคำตอบที่ยอดเยี่ยม แต่ไม่ตอบคำถาม ค่าควรเป็นสตริงไม่ใช่วัตถุ
Dem Pilafian

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()swoops ในกรณีการใช้งานอื่น วิธีทำอย่างชาญฉลาด!
แดน

ใครมีรุ่นที่พิมพ์แล้วนี้?
mr.bjerre

ความจริงก็คือเป็นความจริงทางคณิตศาสตร์ที่คุณสามารถใช้การกระทำซ้ำ ๆ ได้อย่างแท้จริงโดยใช้การลด / การฉีดเนื่องจากการลดเป็นไอโซมอร์ฟิกในรายการ อย่างไรก็ตามความยืดหยุ่นนั้นมาพร้อมกับราคาที่สามารถอ่านได้ อย่าใช้_.reduceเว้นแต่ว่าจะแสดงสิ่งที่คุณกำลังพยายามทำอย่างถูกต้อง: มันบดบังจุดของโค้ดอย่างมากในกรณีอื่น ๆ โดยส่วนตัวแล้วฉันชอบ_.zipObjectวิธีแก้ปัญหาโดย @djechlin - ล้มเหลวที่_.keyBy/ _.mapValuesวิธีการ
Robert Fischer

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

(ขอบคุณ Ben Steward ความคิดดี ... )


อาจจะรวมไว้ในฟังก์ชันหลักเพื่อให้ผู้ใช้สามารถกำหนดได้ว่าจะใช้คีย์ใดโดยการส่งผ่านเหมือนที่ OP มี
Ben Steward

11

คุณสามารถใช้หนึ่งซับจาวาสคริปต์กับวิธีการลดอาร์เรย์และการทำลาย 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-yuri

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

ป้อนคำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.