【问题标题】:Javascript object reorganization with performanceJavascript 对象重组与性能
【发布时间】:2017-11-27 11:52:17
【问题描述】:

我正在解决一个问题,我必须将一组对象从一种形式分组到另一种形式中。

一个例子胜过1000字:

var initialData = [
  {
    house: { id: 1, text: "white" },
    room: { id: 1, text: "red" },
    price: 2.1
  },
  {
    house: { id: 1, text: "white" },
    room: { id: 2, text: "blue" },
    price: 3.1
  },
  {
    house: { id: 1, text: "white" },
    room: { id: 3, text: "red" },
    price: 5.8
  },
  {
    house: { id: 2, text: "black" },
    room: { id: 1, text: "yellow" },
    price: 9.1
  },
  {
    house: { id: 2, text: "black" },
    room: { id: 2, text: "green" },
    price: 7.7
  },
];

新对象应该是这样的:

var finalObject = {
  houses: [
    {
      id: 1, text: "white",
      rooms: [
        { id: 1, text: "red", price: "2.1" },
        { id: 2, text: "blue", price: "3.1" },
        { id: 3, text: "red", price: "5.8" }
      ]
    },
    {
      id: 2, text: "black",
      rooms: [
        { id: 1, text: "yellow", price: "9.1" },
        { id: 2, text: "green", price: "7.7" }
      ]
    }
  ]
};

我必须找到带有所有房间的独特房屋,并且还要从房间内的初始对象中添加每个价格。

我想知道哪种方法是最好的方法,因为我将拥有大量元素?

我有一些关于多个循环的想法,但对我来说,我的解决方案似乎有点过于复杂。

更新:我的问题与重复的候选者不同,因为我不使用 lodash,并且我的对象必须进行一些重构,而不仅仅是重新组合。

可能的解决方案(受@Gael 的回答启发)

finalObject = {}

for (var i = 0; i < initialData.length; ++i) {
  var item = initialData[i];
  var id = item.house.id;
  if(!finalObject[id]) {
    finalObject[id] = item.house;
    finalObject[id].rooms = [];
  }
  var room = item.room;
  room.price = item.price;

  finalObject[id].rooms.push(room);
}

console.log(finalObject);

【问题讨论】:

  • 看起来你只需要一个循环。您可以遍历每个元素并将其添加到一个新数组中,然后根据房屋、房间和 ID 对其进行分组。
  • 您应该发布这些想法以及您迄今为止所写的内容以解决问题。

标签: javascript arrays filtering javascript-objects


【解决方案1】:

你应该使用地图:

var myMap = new Map();

var keyObj = {}, // ideally your room object with id


// setting the values
myMap.set(keyString, "value associated with 'a string'"); // not recommended for your case

或者:

myMap.set(keyObj, 'value associated with keyObj'); // should be rooms

myMap.size; // the number of items you added

【讨论】:

  • 这只是一个不同的数据结构,但是按照我需要的方式分组的策略是什么?
  • @V.Sambor 制作房屋类键和房间数组的对象,其中包含房间对象的值。
  • 感谢您的帮助,我要试试这个,马上回来! :)
【解决方案2】:

Array#reduce 与辅助对象一起使用:

var initialData = [{"house":{"id":1,"text":"white"},"room":{"id":1,"text":"red"},"price":2.1},{"house":{"id":1,"text":"white"},"room":{"id":2,"text":"blue"},"price":3.1},{"house":{"id":1,"text":"white"},"room":{"id":3,"text":"red"},"price":5.8},{"house":{"id":2,"text":"black"},"room":{"id":1,"text":"yellow"},"price":9.1},{"house":{"id":2,"text":"black"},"room":{"id":2,"text":"green"},"price":7.7}];

var dict = {}; // helper object
var result = initialData.reduce(function(houses, obj) { // reduce the data
  var house = dict[obj.house.id]; // get the house from the dict by id
  
  if(!house) { // if house wasn't found
    house = Object.assign({}, obj.house, { rooms: [] }); // create a new house object
    houses.push(house); // push it into the array of houses
    dict[house.id] = house; // add it to the dict by id
  }
  
  house.rooms.push(obj.room); // push the room to the current house
  
  return houses;
}, []);

console.log(result);

你也可以使用 ES6 Map and spread 语法来实现它:

const initialData = [{"house":{"id":1,"text":"white"},"room":{"id":1,"text":"red"},"price":2.1},{"house":{"id":1,"text":"white"},"room":{"id":2,"text":"blue"},"price":3.1},{"house":{"id":1,"text":"white"},"room":{"id":3,"text":"red"},"price":5.8},{"house":{"id":2,"text":"black"},"room":{"id":1,"text":"yellow"},"price":9.1},{"house":{"id":2,"text":"black"},"room":{"id":2,"text":"green"},"price":7.7}];

const result = [...initialData.reduce((houses, { house, room }) => { // reduce the data to a Map
  const currentHouse = houses.get(house.id) || Object.assign({}, house, { rooms: [] }); // get the current house from the map by id, or create a new one
  
  currentHouse.rooms.push(room); // push the room to the current house
  
  return houses.set(currentHouse.id, currentHouse); // set the house to the map, and return it
}, new Map()).values()]; // get the values of the map and spread to an array

console.log(result);

【讨论】:

    【解决方案3】:

    取决于是否要保留初始数据会影响解决方案。我假设您想保留原始对象并生成一个新对象。

    如果您使用Map 对象来记住现有房屋在id 属性旁边的位置,则可以在单个循环中执行此操作。如果房子已经插入到结果中,你只需要添加新房间。否则,您需要创建一个新的房屋对象并将其索引存储在地图中。

    function transformHouses(houses) {
      const houseMap = new Map();
      const result = {houses: []};
    
      for(const house of houses) {
        if(houseMap.has(house.id)) {
          const index = houseMap.get(house.id);
          const room = Object.assign({price: house.price}, house.room);
    
          result.houses[index].rooms.push(room);
        } else {
          const room = Object.assign({price: house.price}, house.room);
          const entry = Object.assign({rooms: [room]}, house.house)
    
          housesMap.set(house.id, result.houses.length);
          result.houses.push(entry);
        }
      }
    
      return result;
    }
    

    【讨论】:

      【解决方案4】:

      var houses= {};
      
      initialData.forEach(function(item){
        
        if( !houses[ item.house ] ){
        
          houses[ item.house ]= item.house;
          houses[ item.house ].rooms= {};
        }
        houses[ item.house ].rooms[ item.room.id ]= item.room;
        houses[ item.house ].rooms[ item.room.id ].price= item.price;
        
      });

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-17
        • 2020-01-16
        • 2018-03-01
        • 2014-01-15
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多