【问题标题】:Create array of objects by key from array of objects从对象数组中按键创建对象数组
【发布时间】:2019-09-09 05:29:53
【问题描述】:

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

在示例数据中,我们按对象的“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'
    }
];

如果有人对此有解决方案,我将不胜感激,至少可以说我目前的尝试是草率的。

【问题讨论】:

  • 请添加您的尝试。为什么最后一项没有包装在数组中?
  • 使用.sort(customCompare) where customCompare = function(a,b){.....}

标签: javascript arrays json object ecmascript-6


【解决方案1】:

查找并删除船舶名称,然后查找每艘船舶的人员。

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 个数组,我试图将原始数组匹配在一起,一个仅包含船舶,然后是基于船舶索引的新数组...
【解决方案2】:

您可以将对象和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; }

【讨论】:

  • 谢谢尼娜,我喜欢使用reduce,我没有考虑过。
  • 这是公认的答案,因为我的数据比示例复杂得多,而且我能够根据我的需要快速修改这个数据,我想其他人也会这样做(只需添加一个额外的如果 item.ship 不存在,则映射以匹配另一个值)。
【解决方案3】:

可能不是性能最高的,但这应该可以。

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

【讨论】:

  • 谢谢哈利,离我拍的不远,但更干净了。
【解决方案4】:

不确定您打算如何使用这些数据,但更简洁的数据结构是否会看起来像船上有人员的对象,而不是船名以冗余方式不断重复的数组?这个数据结构呢?

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

【讨论】:

    【解决方案5】:

    这略有不同,因为它是一个带有键的对象,但这些键包含数组,其中包含您希望如何查看的数据。

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

    【讨论】:

      【解决方案6】:

      这里你有另一种方法,首先,我们使用Array.reduce() 生成一个对象,该对象将按ship 属性对元素进行分组。然后我们在生成的Object.values() 上使用Array.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;}

      【讨论】:

        【解决方案7】:

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

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

        来自文档:

        创建一个由通过迭代器运行集合的每个元素的结果生成的键组成的对象。分组值的顺序由它们在集合中出现的顺序决定。每个键对应的值是负责生成键的元素数组。使用一个参数调用迭代对象:(值)。

        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);
        &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"&gt;&lt;/script&gt;

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            猜你喜欢
            • 2015-03-05
            • 1970-01-01
            • 2016-12-31
            • 2015-11-28
            • 2015-03-22
            • 1970-01-01
            • 2021-08-09
            • 2021-11-19
            相关资源
            最近更新 更多