Thực hiện .join trên giá trị trong mảng của các đối tượng


273

Nếu tôi có một chuỗi các chuỗi, tôi có thể sử dụng .join()phương thức để có được một chuỗi, với mỗi phần tử được phân tách bằng dấu phẩy, như vậy:

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

Tôi có một mảng các đối tượng và tôi muốn thực hiện một thao tác tương tự trên một giá trị được giữ trong đó; từ đó

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

thực hiện joinphương thức chỉ trên namethuộc tính, để đạt được đầu ra như trước.

Hiện tại tôi có chức năng sau:

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

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

  return out.join(", ");
}

Không có gì sai với mã đó, nó hoạt động, nhưng thật bất ngờ tôi đã đi từ một dòng mã đơn giản, cô đọng sang một chức năng rất bắt buộc. Có một cách ngắn gọn hơn, lý tưởng hơn chức năng viết này?


1
Để sử dụng một ngôn ngữ làm ví dụ, một cách Pythonic để làm điều này sẽ là" ,".join([i.name for i in a])
jackweirdy

6
Trong ES6 bạn có thể làm điều này : users.map(x => x.name).join(', ');.
totymedli

Câu trả lời:


496

Nếu bạn muốn ánh xạ các đối tượng đến một cái gì đó (trong trường hợp này là một thuộc tính). Tôi nghĩ Array.prototype.maplà những gì bạn đang tìm kiếm nếu bạn muốn mã hóa chức năng.

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

Trong JavaScript hiện đại:

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

(vĩ cầm)

Nếu bạn muốn hỗ trợ các trình duyệt cũ hơn, không tuân thủ ES5, bạn có thể bắt chước nó (có một polyfill trên trang MDN ở trên). Một cách khác là sử dụng pluckphương thức của dấu gạch dưới :

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

1
Cái này. Tuy nhiên, bạn sẽ cần phải bắt chước thành viên nguyên mẫu .map cho IE <9, nếu bạn cần hỗ trợ các trình duyệt retro này.
Tommi

@Tommi bình luận tốt. Tôi đã thêm một lời giải thích về một polyfill cũng như một gợi ý để sử dụng pluck nếu sử dụng dấu gạch dưới.
Benjamin Gruenbaum

@jackweirdy Tôi rất vui vì tôi có thể giúp :) vì những gì nó đáng giá, giống như bản đồ / thu nhỏ / bộ lọc không phải là 'pythonic' và hiểu là cách khác. Trong tiến trình mới của JavaScript (Harmony) cũng như một số trình duyệt đã có (firefox), bạn đã hiểu được pythonic. Bạn có thể làm [x.name for x of users]( cụ thể wiki.ecmascript.org/doku.php?id=harmony:array_comprehensions ). Đáng nói là, giống như sử dụng map / less / filter không phải là "pythonic", cách khác có thể có trong JavaScript. CoffeeScript rất tuyệt với họ mặc dù coffeescript.org .
Benjamin Gruenbaum

Chỉ cần một bản cập nhật - sự hiểu biết về mảng đã bị loại bỏ khỏi ES6, có thể chúng ta sẽ có được chúng trong ES7.
Benjamin Gruenbaum

Trong coffeescript:users.map((obj) -> obj.name).join(', ')
Kesha Antonov

71

Vâng, bạn luôn có thể ghi đè toStringphương thức của các đối tượng của bạn:

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
Đó là một cách tiếp cận khá thú vị, tôi không nhận ra bạn có thể làm điều này trong JS. Dữ liệu được lấy từ một API, vì vậy nó có thể không phù hợp với trường hợp sử dụng của tôi, nhưng nó chắc chắn là thực phẩm đáng suy nghĩ.
jackweirdy

3
Không có vẻ rất KHÔ
BadHorsie

3
@BadHorsie Không, nó không KHÔ. Nhưng tất nhiên bạn có thể định nghĩa một hàm duy nhất bên ngoài mảng và sau đó gán hàm này cho toStringphương thức của tất cả các mục, sử dụng vòng lặp for. Hoặc bạn có thể sử dụng phương pháp này khi xử lý các hàm xây dựng, bằng cách thêm một toStringphương thức vào thuộc prototypetính cho hàm tạo. Tuy nhiên, ví dụ này chỉ được cho là thể hiện khái niệm cơ bản.
basilikum

13

Tôi cũng đã sử dụng reducephương pháp này, đây là giao diện của nó:

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

Phần (a.name || a)tử đầu tiên được xử lý chính xác, nhưng phần còn lại (trong đóa là một chuỗi và a.namekhông xác định) không được coi là một đối tượng.

Chỉnh sửa: Bây giờ tôi đã tái cấu trúc nó thêm về điều này:

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

mà tôi tin là sạch hơn vì aluôn là một chuỗi, bluôn là một đối tượng (do sử dụng tham số initValue tùy chọn trong reduce)

Chỉnh sửa 6 tháng sau: Ôi tôi đã nghĩ gì. "sạch hơn". Tôi đã tức giận các vị thần mã.


Cảm ơn: D reducekhông được hỗ trợ rộng rãi như map(điều này thật kỳ lạ, vì họ là chị em) nên tôi vẫn đang sử dụng câu trả lời của bạn :)
jackweirdy

Nhìn vào bản chỉnh sửa của tôi 6 tháng sau, tôi đã quyết định rằng tôi sẽ không thuê mình ... Thật xảo quyệt, nhưng không sạch sẽ.
jackweirdy

9

Tôi không biết có cách nào dễ dàng hơn để làm điều đó mà không cần sử dụng thư viện bên ngoài hay không, nhưng cá nhân tôi thích underscore.js có hàng tấn tiện ích để xử lý mảng, bộ sưu tập, v.v.

Với gạch dưới, bạn có thể thực hiện điều này một cách dễ dàng với một dòng mã:

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


Tôi đã từng viết dấu gạch dưới trước đây, tôi đã hy vọng có một cách để làm điều đó trong JS nguyên gốc - đó là một chút
ngu ngốc

( arrtự nhiên là mảng của bạn)
Ed Hinchliffe

đủ công bằng! Bây giờ tôi thấy mình đang sử dụng dấu gạch dưới khắp mọi nơi nên không vấn đề gì.
Ed Hinchliffe

5

Trên nút hoặc ES6 +:

users.map(u => u.name).join(', ')

3

giả sử mảng đối tượng được tham chiếu bởi biến users

Nếu ES6 có thể được sử dụng thì giải pháp đơn giản nhất sẽ là:

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

Nếu không, và lodash có thể được sử dụng như vậy:

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

1

Nếu đối tượng và các phím động: "applications\":{\"1\":\"Element1\",\"2\":\"Element2\"}

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

0

Một chủ đề cũ tôi biết nhưng vẫn siêu phù hợp với bất kỳ ai đi qua đây.

Array.map đã được đề xuất ở đây, đây là một phương pháp tuyệt vời mà tôi sử dụng mọi lúc. Array.reduce cũng được đề cập ...

Cá nhân tôi sẽ sử dụng một Array.reduce cho trường hợp sử dụng này. Tại sao? Mặc dù mã được làm sạch ít hơn / rõ ràng. Đó là một hiệu quả hơn nhiều so với đường ống chức năng bản đồ để tham gia.

Lý do cho điều này là do Array.map phải lặp qua từng phần tử để trả về một mảng mới với tất cả các tên của đối tượng trong mảng. Array.join sau đó lặp lại nội dung của mảng để thực hiện phép nối.

Bạn có thể cải thiện khả năng đọc của jackweirdys giảm câu trả lời bằng cách sử dụng các mẫu chữ để lấy mã trên một dòng. "Được hỗ trợ trong tất cả các trình duyệt hiện đại"

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

0

không chắc chắn, nhưng tất cả các câu trả lời này tho chúng hoạt động nhưng không tối ưu vì chúng đang thực hiện hai lần quét và bạn có thể thực hiện việc này trong một lần quét. Mặc dù O (2n) được coi là O (n) luôn tốt hơn để có O (n) thực sự.

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

Điều này có thể trông giống như trường học cũ, nhưng cho phép tôi làm điều đó như thế này:

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

-1

thử cái này

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
Đây là chức năng tương tự như trong câu hỏi, ngoại trừ kém linh hoạt hơn vì bạn đã mã hóa cứng name thuộc tính. ( a[i].nameKhông không sử dụng của bạn chức năng của nameđối số, nó tương đương với a[i]['name'].)
nnnnnn
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.