javascript - Create array of objects by key from array of objects - Stack Overflow

There are a lot of questions like this on here, but I couldn't find one that matched my needs. I&#

There are a lot of questions like this on here, but I couldn't find one that matched my needs. I'm looking for a relatively simple solution on how to stack objects in an array into new arrays based on a key.

In the example data we're grouping the objects by their "ship" key.

Original data:

 var myObjArray = [
    {
        name:'Malcolm Reynolds',
        ship:'Serenity'
    },
    {
        name: 'Carmen Ibanez',
        ship: 'Rodger Young',
    },
    {
        name: 'Zander Barcalow',
        ship: 'Rodger Young',
    },
    {
        name:'Hoban Washburne',
        ship:'Serenity'
    },
    {
        name:'James Kirk',
        ship:'USS Enterprise'
    }
];

Restructured Data:

    var myNewObjArray = [
    [{
        name:'Malcolm Reynolds',
        ship:'Serenity'
    },
    {
        name:'Hoban Washburne',
        ship:'Serenity'
    }],
    [{
        name: 'Carmen Ibanez',
        ship: 'Rodger Young',
    },
    {
        name: 'Zander Barcalow',
        ship: 'Rodger Young',
    }],
    {
        name:'James Kirk', // optionally also stick in an array
        ship:'USS Enterprise'
    }
];

If anyone has a solution for this I'd appreciate it, my current attempt is sloppy to say the least.

There are a lot of questions like this on here, but I couldn't find one that matched my needs. I'm looking for a relatively simple solution on how to stack objects in an array into new arrays based on a key.

In the example data we're grouping the objects by their "ship" key.

Original data:

 var myObjArray = [
    {
        name:'Malcolm Reynolds',
        ship:'Serenity'
    },
    {
        name: 'Carmen Ibanez',
        ship: 'Rodger Young',
    },
    {
        name: 'Zander Barcalow',
        ship: 'Rodger Young',
    },
    {
        name:'Hoban Washburne',
        ship:'Serenity'
    },
    {
        name:'James Kirk',
        ship:'USS Enterprise'
    }
];

Restructured Data:

    var myNewObjArray = [
    [{
        name:'Malcolm Reynolds',
        ship:'Serenity'
    },
    {
        name:'Hoban Washburne',
        ship:'Serenity'
    }],
    [{
        name: 'Carmen Ibanez',
        ship: 'Rodger Young',
    },
    {
        name: 'Zander Barcalow',
        ship: 'Rodger Young',
    }],
    {
        name:'James Kirk', // optionally also stick in an array
        ship:'USS Enterprise'
    }
];

If anyone has a solution for this I'd appreciate it, my current attempt is sloppy to say the least.

Share Improve this question edited Apr 18, 2019 at 20:54 user47589 asked Apr 18, 2019 at 20:39 Ian GrayIan Gray 3871 gold badge4 silver badges15 bronze badges 2
  • 2 please add your attempt. why is the last item not wrapped in an array? – Nina Scholz Commented Apr 18, 2019 at 20:42
  • use .sort(customCompare) where customCompare = function(a,b){.....} – Alex Kudryashev Commented Apr 18, 2019 at 20:46
Add a ment  | 

8 Answers 8

Reset to default 3

You could take an object for and the ship value as key for the same group. For the result take only the values of the object.

var data = [{ name: 'Malcolm Reynolds', ship: 'Serenity' }, { name: 'Carmen Ibanez', ship: 'Rodger Young' }, { name: 'Zander Barcalow', ship: 'Rodger Young' }, { name: 'Hoban Washburne', ship: 'Serenity' }, { name: 'James Kirk', ship: 'USS Enterprise' }],
    grouped = Object.values(data.reduce((r, o) => {
        if (!r[o.ship]) {
            r[o.ship] = o;
            return r;
        }
        if (!Array.isArray(r[o.ship])) r[o.ship] = [r[o.ship]];
        r[o.ship].push(o);
        return r;
    }, {}));

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

An approach with a Map

var data = [{ name: 'Malcolm Reynolds', ship: 'Serenity' }, { name: 'Carmen Ibanez', ship: 'Rodger Young' }, { name: 'Zander Barcalow', ship: 'Rodger Young' }, { name: 'Hoban Washburne', ship: 'Serenity' }, { name: 'James Kirk', ship: 'USS Enterprise' }],
    grouped = Array.from(
        data
            .reduce((m, o) => m.set(o.ship, [...(m.get(o.ship) || []), o]), new Map)
            .values(),
        a => a.length === 1 ? a[0] : a
    );

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Find and deduplicate names of ships, then find personnel for every ship.

const myObjArray = [
    {
        name:'Malcolm Reynolds',
        ship:'Serenity'
    },
    {
        name: 'Carmen Ibanez',
        ship: 'Rodger Young',
    },
    {
        name: 'Zander Barcalow',
        ship: 'Rodger Young',
    },
    {
        name:'Hoban Washburne',
        ship:'Serenity'
    },
    {
        name:'James Kirk',
        ship:'USS Enterprise'
    }
];

const ships = myObjArray.map(({ship}) => ship).filter((ship, i, arr) => arr.indexOf(ship) === i);

const personnelArray = ships.map(ship => myObjArray.filter(entry => entry.ship === ship));

console.log(personnelArray);

Another clean and elegant solution would be working with Lodash.

First, group by the array with the relevant key.Then,Get the values from the object.

From the docs :

Creates an object posed of keys generated from the results of running each element of collection thru iteratee. The order of grouped values is determined by the order they occur in collection. The corresponding value of each key is an array of elements responsible for generating the key. The iteratee is invoked with one argument: (value).

const  myObjArray = [
{
    name:'Malcolm Reynolds',
    ship:'Serenity'
},
{
    name: 'Carmen Ibanez',
    ship: 'Rodger Young',
},
{
    name: 'Zander Barcalow',
    ship: 'Rodger Young',
},
{
    name:'Hoban Washburne',
    ship:'Serenity'
},
{
    name:'James Kirk',
    ship:'USS Enterprise'
}
];

var result =_.values((_.groupBy(myObjArray , 'ship')));

console.log(result);
<script src="https://cdnjs.cloudflare./ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>

Probably not the most performant but this should work.

var tempObj = {};
myObjArray.forEach((item)=>{
  var ship = item.ship;
  if (!tempObj.hasOwnProperty(ship)) {
    tempObj[ship] = []; //create the key in the key in the obj and init to an empty array
  }
  tempObj[ship].push(item); //add the item to the array
});

var myNewObjArray = [];

for (key in tempObj) {
  myNewObjArray.push([]); //add a new array for each key in the tempObj
  tempObj[key].forEach((item)=>{ //iterate over the array of items in the tempObj for that key
    myNewObjArray[myNewObjArray.length-1].push(item); //add the item to the last array in the object which should have been created.
  });
}

This is slightly different in that it's an object with keys, but that those keys contain arrays with the data how you want to see it.

var newObject = {};

for (var i in myObjArray) {
     var newKey = myObjArray[i].ship.replace(/\s+/g, '');
   if (typeof(newObject[newKey]) == "undefined") newObject[newKey] = [];
   newObject[newKey].push({
        name: myObjArray[i].name, ship: myObjArray[i].ship
   });
}

Not sure how you plan on using the data but would a more concise data structure look something like an object where the ship has staff rather than an array of arrays where the ship name is continually repeated in a redundant way? What about this data structure?

var myObjArray = [
    {
        name:'Malcolm Reynolds',
        ship:'Serenity'
    },
    {
        name: 'Carmen Ibanez',
        ship: 'Rodger Young',
    },
    {
        name: 'Zander Barcalow',
        ship: 'Rodger Young',
    },
    {
        name:'Hoban Washburne',
        ship:'Serenity'
    },
    {
        name:'James Kirk',
        ship:'USS Enterprise'
    }
];

const staffShips = data => data.reduce((ships, item) => {
  const ship = ships[item.ship];
  if (ship) {
    ship.push(item.name);
  } else {
    ships[item.ship] = [ item.name ];
  }
  return ships;
}, {});

console.log(staffShips(myObjArray));

Here you have another approach, first, we use Array.reduce() to generate an object that will group elements by the ship property. Then we use Array.map() over the generated Object.values() to drop the array if only holds one element. The map could be optional if you don't really need this last step.

var myObjArray = [
  {name:'Malcolm Reynolds', ship:'Serenity'},
  {name: 'Carmen Ibanez', ship: 'Rodger Young'},
  {name: 'Zander Barcalow', ship: 'Rodger Young'},
  {name:'Hoban Washburne', ship:'Serenity'},
  {name:'James Kirk', ship:'USS Enterprise'}
];

let res = myObjArray.reduce((acc, obj) =>
{
    acc[obj.ship] = acc[obj.ship] || [];
    acc[obj.ship].push(obj);
    return acc;
}, {});

res = Object.values(res).map(arr => (arr.length <= 1 ? arr[0] : arr));

console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

In Javascript, to group objects by property, Array.prototype.reduce() method can be used to consolidate the input array data into a set of results, grouped by a key( in this case 'ship'). Use Object.values to extract the values from the resulting set by dropping the keys

var data = [
{ name: 'Malcolm Reynolds', ship: 'Serenity' },
{ name: 'Carmen Ibanez', ship: 'Rodger Young' }, 
{ name: 'Zander Barcalow', ship: 'Rodger Young' }, 
{ name: 'Hoban Washburne', ship: 'Serenity' }, 
{ name: 'James Kirk', ship: 'USS Enterprise' }];

var myNewObjArray = data.reduce((res,obj) =>{
const key = obj.ship;
if(!res[key]){
res[key] = [];
}
res[key].push(obj)
return res;
}, {});

console.log(Object.values(myNewObjArray));

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742304740a4418715.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信