Выполнить .join по значению в массиве объектов

Если у меня есть массив строк, я могу использовать метод .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

Если вы хотите сопоставить объекты с чем-либо (в данном случае это свойство). Я думаю, что 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(",")

Ответ 2

Ну, вы всегда можете переопределить метод 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"

Ответ 3

Я также сталкивался с использованием метода 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 is undefined) не рассматривается как объект.

Изменить: теперь я отредактировал его дальше:

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

который, я считаю, более чистым, поскольку a всегда является строкой, b всегда является объектом (из-за использования необязательного параметра initialValue /a > in reduce)

Редактировать 6 месяцев спустя: О, о чем я думал. "очиститель". Я разозлил код Богов.

Ответ 4

Я не знаю, есть ли более простой способ сделать это, не используя внешнюю библиотеку, но я лично люблю underscore.js, у которой есть множество утилит для работы с массивами, коллекциями и т.д.

С подчеркиванием вы можете сделать это легко с помощью одной строки кода:

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

Ответ 5

Вкл. node или ES6:

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

Ответ 6

позволяет сказать, что массив объектов ссылается на переменную users

Если ES6 можно использовать, самым простым решением будет:

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

Если нет, и lodash можно использовать так:

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

Ответ 7

Если объект и динамические ключи: "applications\":{\"1\":\"Element1\",\"2\":\"Element2\"}

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

Ответ 8

Старая ветка, которую я знаю, но все еще очень важна для всех, кто сталкивался с этим

Здесь был предложен 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}');

Ответ 9

Не уверен, но все это отвечает тем, что они работают, но не являются оптимальными, так как выполняют два сканирования, и вы можете выполнить это в одном сканировании. Даже если 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');

Ответ 10

попробуйте это

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"