Perform .join on value in array of objects

JavascriptArraysObject

Javascript Problem Overview


If I have an array of strings, I can use the .join() method to get a single string, with each element separated by commas, like so:

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

I have an array of objects, and I’d like to perform a similar operation on a value held within it; so from

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

perform the join method only on the name attribute, to achieve the same output as before.

Currently I have the following function:

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

There’s nothing wrong with that code, it works, but all of a sudden I’ve gone from a simple, succinct line of code to a very imperative function. Is there a more succinct, ideally more functional way of writing this?

Javascript Solutions


Solution 1 - Javascript

If you want to map objects to something (in this case a property). I think Array.prototype.map is what you're looking for if you want to code functionally.

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

In modern JavaScript:

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

(fiddle)

If you want to support older browsers, that are not ES5 compliant you can shim it (there is a polyfill on the MDN page above). Another alternative would be to use underscorejs's pluck method:

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

Solution 2 - Javascript

Well you can always override the toString method of your objects:

    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(", ");
    console.log(result);

Solution 3 - Javascript

I've also come across using the reduce method, this is what it looks like:

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

The (a.name || a) is so the first element is treated correctly, but the rest (where a is a string, and so a.name is undefined) isn't treated as an object.

Edit: I've now refactored it further to this:

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

which I believe is cleaner as a is always a string, b is always an object (due to the use of the optional initialValue parameter in reduce)

Edit 6 months later: Oh what was I thinking. "cleaner". I've angered the code Gods.

Solution 4 - Javascript

On node or ES6+:

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

Solution 5 - Javascript

I don't know if there's an easier way to do it without using an external library, but I personally love underscore.js which has tons of utilities for dealing with arrays, collections etc.

With underscore you could do this easily with one line of code:

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

Solution 6 - Javascript

lets say the objects array is referenced by the variable users

If ES6 can be used then the easiest solution will be:

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

If not, and lodash can be used so :

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

Solution 7 - Javascript

If object and dynamical keys: "applications\":{\"1\":\"Element1\",\"2\":\"Element2\"}

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

Solution 8 - Javascript

An old thread I know but still super relevant to anyone coming across this.

Array.map has been suggested here which is an awesome method that I use all the time. Array.reduce was also mentioned...

I would personally use an Array.reduce for this use case. Why? Despite the code being slightly less clean/clear. It is a much more efficient than piping the map function to a join.

The reason for this is because Array.map has to loop over each element to return a new array with all of the names of the object in the array. Array.join then loops over the contents of array to perform the join.

You can improve the readability of jackweirdys reduce answer by using template literals to get the code on to a single line. "Supported in all modern browsers too"

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

Solution 9 - Javascript

not sure, but all this answers tho they work but are not optiomal since the are performing two scans and you can perform this in a single scan. Even though O(2n) is considered O(n) is always better to have a true 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;
}

This might look like old school, but allows me to do thig like this:

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

Solution 10 - Javascript

you can convert to array so get object name

var objs = [
      {name: "Joe", age: 22},
      {name: "Kevin", age: 24},
      {name: "Peter", age: 21}
    ];
document.body.innerHTML = Object.values(objs).map(function(obj){
   return obj.name;
});

Solution 11 - Javascript

Easiest way:

const oldArrayOfObjects = [
{name: "Bob", age:40}, 
{name: "Andrew", age:25}, 
{name: "Peter", age:30}];
const newArrayOfStringNames = oldArrayOfObjects.map((OA) => OA.name);
const newArrayOfAges = oldArrayOfObjects.map((OA) => OA.age);
console.log({newArrayOfStringNames, newArrayOfAges})

Solution 12 - Javascript

try this

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"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjackweirdyView Question on Stackoverflow
Solution 1 - JavascriptBenjamin GruenbaumView Answer on Stackoverflow
Solution 2 - JavascriptbasilikumView Answer on Stackoverflow
Solution 3 - JavascriptjackweirdyView Answer on Stackoverflow
Solution 4 - JavascriptarielView Answer on Stackoverflow
Solution 5 - JavascriptEd_View Answer on Stackoverflow
Solution 6 - JavascriptC'estLaVieView Answer on Stackoverflow
Solution 7 - JavascriptDavron AchilovView Answer on Stackoverflow
Solution 8 - JavascriptNigelliView Answer on Stackoverflow
Solution 9 - JavascriptJorge AguilarView Answer on Stackoverflow
Solution 10 - JavascriptSAWA4DView Answer on Stackoverflow
Solution 11 - JavascriptJPMCView Answer on Stackoverflow
Solution 12 - JavascriptharipdsView Answer on Stackoverflow