从对象数组中按键创建对象数组

4

这里有很多类似的问题,但我找不到符合我的需求的。我正在寻找一个相对简单的解决方案,用于根据键将数组中的对象堆叠到新数组中。

在示例数据中,我们按其“ship”键对对象进行分组。

原始数据:

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

重组数据:

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

如果有人有解决方法,我会非常感激,因为我的当前尝试可以说是很粗糙了。

2
为什么最后一个项目没有包含在数组中? - Nina Scholz
请使用.sort(customCompare),其中customCompare = function(a,b){.....} - Alex Kudryashev
8个回答

3
找到并去重船只名称,然后为每艘船找到人员。

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


非常简单干净,谢谢...我的版本包括3个数组,我试图将它们匹配在一起:原始数组、仅包含船只的数组,以及一个基于仅包含船只的索引的新数组... - Ian Gray

3

您可以将对象和ship值作为同一组的键。对于结果,只取对象的值。

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

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


谢谢Nina,我喜欢使用reduce,我没有考虑过这一点。 - Ian Gray
这是被接受的答案,因为我的数据比示例复杂得多,我能够快速修改它以满足我的需求,我想其他人也会这样做(只需要添加一个额外的映射来匹配另一个值,如果 item.ship 不存在)。 - Ian Gray

1
另一个干净优雅的解决方案是使用Lodash

首先,通过相关键对数组进行分组。然后,从对象中获取值。

从文档中可以看到:

通过运行集合中每个元素的结果生成键来创建由键组成的对象。分组值的顺序由它们在集合中出现的顺序确定。每个键的相应值是生成该键的元素的数组。iteratee使用一个参数调用:(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.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>


0

可能不是最高效的,但这应该能够工作。

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

1
谢谢Harry,跟我所拼凑的差不多但更整洁。 - Ian Gray

0

这有点不同,因为它是一个带有键的对象,但是这些键包含用于展示数据的数组。

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

0
不确定您计划如何使用数据,但更简洁的数据结构是否看起来像一个对象,其中船只有员工,而不是一个数组的数组,其中船名以冗余方式不断重复?这个数据结构怎么样?

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


0

这里有另一个方法,首先我们使用 Array.reduce() 生成一个对象,该对象将按船舶属性分组元素。然后我们使用 Array.map() 在生成的 Object.values() 上操作,以删除仅包含一个元素的数组。如果您不需要此最后一步,则可以选择不使用 map。

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


0
在JavaScript中,要按属性对对象进行分组,可以使用Array.prototype.reduce()方法将输入数组数据合并为一组结果,按键(在此情况下为“ship”)进行分组。 使用Object.values从生成的集合中提取值,丢弃键。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接