ดำเนินการ. เข้าร่วมกับค่าในอาร์เรย์ของวัตถุ


273

ถ้าฉันมีอาเรย์ของสตริงฉันสามารถใช้.join()เมธอดรับสตริงเดี่ยวโดยที่แต่ละองค์ประกอบคั่นด้วยเครื่องหมายจุลภาคดังนี้:

["Joe", "Kevin", "Peter"].join(", ") // => "Joe, Kevin, Peter"

ฉันมีชุดของวัตถุและฉันต้องการที่จะดำเนินการคล้ายกันกับค่าที่เก็บไว้ในนั้น ดังนั้นจาก

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
]

ทำjoinวิธีการเฉพาะกับnameคุณลักษณะเพื่อให้ได้ผลลัพธ์เช่นเดียวกับก่อน

ขณะนี้ฉันมีฟังก์ชั่นต่อไปนี้:

function joinObj(a, attr){
  var out = [];

  for (var i = 0; i < a.length; i++){
    out.push(a[i][attr]);
  }

  return out.join(", ");
}

ไม่มีอะไรผิดปกติกับรหัสนั้นมันใช้งานได้ แต่ในทันใดฉันได้หายไปจากบรรทัดที่เรียบง่ายและชัดเจนไปยังฟังก์ชั่นที่จำเป็นมาก ๆ มีวิธีการเขียนที่กระชับกว่าและใช้งานง่ายกว่านี้ไหม?


1
หากต้องการใช้ภาษาหนึ่งเป็นตัวอย่างวิธีการทำแบบ Pythonic คือ" ,".join([i.name for i in a])
jackweirdy

6
ใน ES6 users.map(x => x.name).join(', ');คุณสามารถทำเช่นนี้:
totymedli

คำตอบ:


496

ถ้าคุณต้องการแมปวัตถุกับบางสิ่ง (ในกรณีนี้คือคุณสมบัติ) ฉันคิดว่าArray.prototype.mapเป็นสิ่งที่คุณกำลังมองหาหากคุณต้องการโค้ดตามหน้าที่

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
].map(function(elem){
    return elem.name;
}).join(",");

ใน JavaScript ที่ทันสมัย:

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
].map(e => e.name).join(",");

(ซอ)

หากคุณต้องการสนับสนุนเบราว์เซอร์รุ่นเก่านั่นไม่ใช่ES5 ที่เข้ากันได้คุณสามารถใช้มัน (มีโพลีฟิลในหน้า MDN ด้านบน) อีกทางเลือกหนึ่งคือการใช้pluckวิธีการของ underscorejs :

var users = [
      {name: "Joe", age: 22},
      {name: "Kevin", age: 24},
      {name: "Peter", age: 21}
    ];
var result = _.pluck(users,'name').join(",")

1
อันนี้. อย่างไรก็ตามคุณจะต้องชิมสมาชิกต้นแบบ. map สำหรับ IE <9 หากคุณต้องการสนับสนุนเบราว์เซอร์ย้อนยุคนี้
Tommi

@ Tomi ความคิดเห็นที่ดี ฉันได้เพิ่มคำอธิบายเกี่ยวกับโพลีฟิลรวมถึงคำแนะนำในการใช้ถอนเมื่อใช้ขีดล่าง
Benjamin Gruenbaum

@ jackweirdy ฉันดีใจที่ฉันสามารถช่วย :) สำหรับสิ่งที่มันคุ้มค่าเช่นเดียวกับแผนที่ / ลด / กรองไม่ได้เป็น 'pythonic' และความเข้าใจเป็นวิธีอื่นถือ ในสเป็คใหม่ของ JavaScript ที่กำลังดำเนินการ (Harmony) รวมถึงเบราว์เซอร์บางตัวที่มีอยู่แล้ว (firefox) คุณมีความเข้าใจแบบ pythonic คุณสามารถทำได้[x.name for x of users](ข้อมูลจำเพาะwiki.ecmascript.org/doku.php?id=harmony:array_comprehensions ) เป็นมูลค่าการกล่าวขวัญว่าเช่นเดียวกับการใช้แผนที่ / ลด / กรองไม่มาก 'pythonic' วิธีอื่นอาจถือใน JavaScript CoffeeScript เย็นกับพวกเขาแม้ว่าcoffeescript.org
Benjamin Gruenbaum

เพียงแค่การอัปเดต - ความเข้าใจของอาร์เรย์ได้ลดลงจาก ES6 บางทีเราจะรับพวกมันใน ES7
Benjamin Gruenbaum

ในกาแฟ:users.map((obj) -> obj.name).join(', ')
Kesha Antonov

71

คุณสามารถแทนที่toStringวิธีของวัตถุของคุณได้ตลอดเวลา:

var arr = [
    {name: "Joe", age: 22, toString: function(){return this.name;}},
    {name: "Kevin", age: 24, toString: function(){return this.name;}},
    {name: "Peter", age: 21, toString: function(){return this.name;}}
];

var result = arr.join(", ");
//result = "Joe, Kevin, Peter"

2
นั่นเป็นวิธีที่น่าสนใจมากฉันไม่ทราบว่าคุณสามารถทำได้ใน JS ข้อมูลมาจาก API แม้ว่าดังนั้นจึงอาจไม่เหมาะกับกรณีการใช้งานของฉัน แต่มันเป็นอาหารสำหรับความคิด
jackweirdy

3
ดูเหมือนจะไม่แห้งมาก
BadHorsie

3
@BadHorsie ไม่ไม่ใช่ DRY แต่แน่นอนคุณสามารถกำหนดฟังก์ชั่นเดียวที่อยู่ด้านนอกของอาเรย์แล้วกำหนดฟังก์ชั่นนี้ให้กับtoStringวิธีการของรายการทั้งหมดโดยใช้ for-loop หรือคุณสามารถใช้วิธีนี้เมื่อจัดการกับฟังก์ชั่นคอนสตรัคโดยการเพิ่มtoStringวิธีการหนึ่งไปยังprototypeคุณสมบัติสำหรับตัวสร้าง อย่างไรก็ตามตัวอย่างนี้ก็ควรจะแสดงแนวคิดพื้นฐาน
basilikum

13

ฉันเคยเจอreduceวิธีใช้นี่คือสิ่งที่ดูเหมือน:

[
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
].reduce(function (a, b) {return (a.name || a) + ", " + b.name})

(a.name || a)จึงเป็นองค์ประกอบแรกได้รับการปฏิบัติอย่างถูกต้อง แต่ส่วนที่เหลือ (ในกรณีที่aเป็นสตริงและอื่น ๆa.nameจะไม่ได้กำหนด) ไม่ได้รับการรักษาเป็นวัตถุ

แก้ไข: ตอนนี้ฉัน refactored มันต่อไปนี้:

x.reduce(function(a, b) {return a + ["", ", "][+!!a.length] + b.name;}, "");

ซึ่งฉันเชื่อว่าสะอาดกว่าaเสมอสตริงbเป็นวัตถุเสมอ (เนื่องจากการใช้พารามิเตอร์ initialValue ตัวเลือกในreduce)

แก้ไข 6 เดือนต่อมา: โอ้ฉันกำลังคิดอะไรอยู่ "ทำความสะอาด" ฉันโกรธรหัสเทพเจ้า


ขอขอบคุณ: D reduceไม่เป็นที่ได้รับการสนับสนุนอย่างกว้างขวางว่าเป็นmap(ซึ่งเป็นลางให้พวกเขาชนิดของน้องสาวกำลัง) ดังนั้นฉันยังคงใช้คำตอบของคุณ :)
jackweirdy

เมื่อดูการแก้ไขของฉัน 6 เดือนต่อมาฉันตัดสินใจแล้วว่าจะไม่จ้างตัวเอง ... มันช่างมีฝีมือ แต่ไม่สะอาด
jackweirdy

9

ฉันไม่รู้ว่ามีวิธีที่ง่ายกว่าในการทำโดยไม่ต้องใช้ห้องสมุดภายนอกหรือไม่ แต่ฉันชอบ underscore.jsซึ่งมีสาธารณูปโภคมากมายสำหรับจัดการกับอาร์เรย์คอลเลกชันและอื่น ๆ

ด้วยการขีดเส้นใต้คุณสามารถทำได้อย่างง่ายดายด้วยโค้ดหนึ่งบรรทัด:

_.pluck(arr, 'name').join(', ')


ฉันเคยขีดเส้นใต้มาก่อนฉันหวังว่าจะมีวิธีที่จะทำได้ในภาษาพื้นเมืองของ JS แม้ว่า - มันเป็นบิตที่บ้าที่จะดึงเข้าไปในห้องสมุดทั้งหมดเพื่อใช้วิธีหนึ่งครั้งเดียว :)
jackweirdy

( arrอาเรย์ของคุณอยู่ที่ไหนตามธรรมชาติ)
Ed Hinchliffe

ยุติธรรมพอ! ฉันพบว่าตัวเองใช้ขีดเส้นใต้ทั่วสถานที่ในขณะนี้ดังนั้นจึงไม่เป็นปัญหา
Ed Hinchliffe


3

สมมติว่าอาร์เรย์วัตถุนั้นถูกอ้างอิงโดยตัวแปร users

หากสามารถใช้ ES6 ได้โซลูชั่นที่ง่ายที่สุดจะเป็น:

users.map(user => user.name).join(', ');

หากไม่สามารถใช้งานและlodashได้:

 _.map(users, function(user) {
     return user.name;
 }).join(', ');

2

หากวัตถุและกุญแจแบบไดนามิก: "applications\":{\"1\":\"Element1\",\"2\":\"Element2\"}

Object.keys(myObject).map(function (key, index) {
    return myObject[key]
}).join(', ')

0

หัวข้อเก่าที่ฉันรู้ แต่ก็ยังมีความเกี่ยวข้องอย่างยิ่งกับทุกคนที่เจอสิ่งนี้

Array.map ได้รับการแนะนำที่นี่ซึ่งเป็นวิธีที่ยอดเยี่ยมที่ฉันใช้ตลอดเวลา Array.reduce ถูกกล่าวถึงยัง ...

ฉันจะใช้ Array.reduce เป็นการส่วนตัวสำหรับกรณีการใช้งานนี้ ทำไม? แม้จะมีรหัสที่ชัดเจนน้อยลง / ชัดเจน มันมีประสิทธิภาพมากกว่าการวางฟังก์ชั่นแผนที่เพื่อเข้าร่วม

เหตุผลนี้เป็นเพราะ Array.map มีการวนซ้ำแต่ละองค์ประกอบเพื่อส่งกลับอาร์เรย์ใหม่ที่มีชื่อทั้งหมดของวัตถุในอาร์เรย์ Array.join จึงวนเนื้อหาของอาร์เรย์เพื่อทำการเข้าร่วม

คุณสามารถปรับปรุงความสามารถในการอ่านของ jackweirdys ลดคำตอบโดยใช้เทมเพลตตัวอักษรเพื่อรับรหัสบนบรรทัดเดียว "รองรับเบราว์เซอร์สมัยใหม่ทุกรุ่นด้วย"

// a one line answer to this question using modern JavaScript
x.reduce((a, b) => `${a.name || a}, ${b.name}`);

0

ไม่แน่ใจ แต่คำตอบทั้งหมดนี้ใช้ได้ แต่ไม่เหมาะสำหรับการสแกนสองครั้งและคุณสามารถทำได้ในการสแกนครั้งเดียว แม้ว่า O (2n) จะถือว่า O (n) จะดีกว่าเสมอที่จะมี O (n) จริง

const Join = (arr, separator, prop) => {
    let combined = '';
    for (var i = 0; i < arr.length; i++) {
        combined = `${combined}${arr[i][prop]}`;
        if (i + 1 < arr.length)
            combined = `${combined}${separator} `;
    }
    return combined;
}

นี่อาจดูเหมือนโรงเรียนเก่า แต่ให้ฉันทำเช่นนี้:

skuCombined = Join(option.SKUs, ',', 'SkuNum');

-1

ลองนี้

var x= [
  {name: "Joe", age: 22},
  {name: "Kevin", age: 24},
  {name: "Peter", age: 21}
]

function joinObj(a, attr) {
  var out = []; 
  for (var i=0; i<a.length; i++) {  
    out.push(a[i][attr]); 
  } 
 return out.join(", ");
}

var z = joinObj(x,'name');
z > "Joe, Kevin, Peter"
var y = joinObj(x,'age');
y > "22, 24, 21"

2
นี่เป็นฟังก์ชั่นเดียวกับคำถามยกเว้นความหลากหลายน้อยกว่าเพราะคุณเขียนโค้ดnameแอตทริบิวต์ไว้อย่างหนัก ( a[i].nameไม่ได้ใช้ฟังก์ชั่นของคุณnameโต้แย้งก็จะเทียบเท่ากับa[i]['name'].)
nnnnnn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.