如何重构对象并在UnderscoreJS中查找总和

时间:2016-11-27 22:17:03

标签: javascript underscore.js

我需要对每个班次(S1,S2,S3)的机器(M1,M2,M3 ......)的键值(K1,K2,K3 ......)求和并创建一个新对象(在下面给出)

我对jquery $.eachforEach方法失去了耐心(因为我需要处理5个级别的对象)并遇到了UnderscoreJS。

我理解我应该为对象http://underscorejs.org/#objects使用多个函数组合,但由于是一个对查询和数据库知之甚少的纯前端人员,我找不到正确的方法来做到这一点。

给定JSON结构:

var data = {
    "28-11":{
        "S1":{
            "M1":{
                "K1": 10,
                "K2": 12,
                "K3": 15
            },
            "M2":{
                "K1": 8,
                "K2": 6,
                "K3": 5
            }
        },
        "S2":{
            "M1":{
                "K1": 8,
                "K2": 6,
                "K3": 5
            },
            "M2":{
                "K1": 10,
                "K2": 12,
                "K3": 15
            }
        }
    }
}

我需要获得以下内容:

var allShiftsData = {
  "28-11":{
    "M1":{
      "K1": 18,
      "K2": 18,
      "K3": 20
    },
    "M2":{
      "K1": 18,
      "K2": 18,
      "K3": 20
    }
  }
}

4 个答案:

答案 0 :(得分:1)

解决这个问题的一种方法是对每个对象属性进行4级迭代,在我们遇到它们时将机器加到结果中:



const data = {"28-11":{"S1":{"M1":{"K1":10,"K2":12,"K3":15},"M2":{"K1":8,"K2":6,"K3":5}},"S2":{"M1":{"K1":8,"K2":6,"K3":5},"M2":{"K1":10,"K2":12,"K3":15}}}};

const {
  keys
} = Object;

const each = (obj, cb) => {
  for (const prop of keys(obj)) {
    cb(obj[prop], prop);
  }
};

const sumShiftsPerDate = (data) => {
  const result = {};
  
  each(data, (shifts, date) => {
    result[date] = {};

    each(shifts, (machines, shift) => {
      each(machines, (machineKeys, machine) => {
        result[date][machine] = result[date][machine] || {};

        each(machineKeys, (keyValue, keyName) => {
          result[date][machine][keyName] = 
            (result[date][machine][keyName] || 0) + keyValue;
        });
      });
    });
  });

  return result;
};

console.log(sumShiftsPerDate(data));




或等效使用下划线each



const data = {"28-11":{"S1":{"M1":{"K1":10,"K2":12,"K3":15},"M2":{"K1":8,"K2":6,"K3":5}},"S2":{"M1":{"K1":8,"K2":6,"K3":5},"M2":{"K1":10,"K2":12,"K3":15}}}};

const sumShiftsPerDate = (data) => {
  const result = {};
  
  _.each(data, (shifts, date) => {
    result[date] = {};

    _.each(shifts, (machines, shift) => {
      _.each(machines, (machineKeys, machine) => {
        result[date][machine] = result[date][machine] || {};

        _.each(machineKeys, (keyValue, keyName) => {
          result[date][machine][keyName] = 
            (result[date][machine][keyName] || 0) + keyValue;
        });
      });
    });
  });

  return result;
};

console.log(sumShiftsPerDate(data));

<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
&#13;
&#13;
&#13;

更实用的方法可以是使用对象映射将每个日期对象从移位容器转换为机器容器,并使用缩减来将它们转换为机器键值的总和。

&#13;
&#13;
const data = {"28-11":{"S1":{"M1":{"K1":10,"K2":12,"K3":15},"M2":{"K1":8,"K2":6,"K3":5}},"S2":{"M1":{"K1":8,"K2":6,"K3":5},"M2":{"K1":10,"K2":12,"K3":15}}}};

const {
  assign, keys
} = Object;

const reduceObject = (obj, cb, initial) => keys(obj).
  reduce((acc, prop) => cb(acc, obj[prop], prop), initial);

const mapObject = (obj, cb) => reduceObject(obj, (result, val, prop) =>
  assign(result, {
    [prop]: cb(val, prop)
  }), {});

const sumObjects = (first, second = {}) =>
  reduceObject(first, (result, val, prop) =>
    assign(result, {
      [prop]: (val || 0) + (second[prop] || 0)
    }), {}
  );

const sumShiftsPerDate = (data) =>
  mapObject(data, (shifts, date) =>
    reduceObject(shifts, (result, shift) =>
      reduceObject(shift, (result, machineKeys, machineName) =>
        assign(result, {
          [machineName]: sumObjects(machineKeys, result[machineName])
        }),
        result
      ),
      {}
    )
  );

console.log(sumShiftsPerDate(data));
&#13;
&#13;
&#13;

以下使用下划线keysextendobjectdefaultsmapObject和{{3 },而不是reduceObject.keysObject.assignES6+ default parameters以及自定义函数mapObjectreduceObject

&#13;
&#13;
const data = {"28-11":{"S1":{"M1":{"K1":10,"K2":12,"K3":15},"M2":{"K1":8,"K2":6,"K3":5}},"S2":{"M1":{"K1":8,"K2":6,"K3":5},"M2":{"K1":10,"K2":12,"K3":15}}}};

// throw in a mixin just for fun :)
// http://underscorejs.org/#mixin
_.mixin({
  sumObjects: (first, second) => 
    _.reduce(first, (result, val, prop) =>
      _.extend(result, _.object(
        [prop], [(val || 0) + (second[prop] || 0)]
      )), {}
    )
});

const sumShiftsPerDate = (data) =>
  _.mapObject(data, (shifts) =>
    _.reduce(shifts, (result, machines) =>
      _.reduce(machines, (result, machineKeys, machineName) =>
        _.extend(result, _.object(
          [machineName], [_.sumObjects(
            machineKeys,
            _.defaults({}, result[machineName]))]
        )),
        result
      ),
      {}
    )
  );

console.log(sumShiftsPerDate(data));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
&#13;
&#13;
&#13;

注意:普通的JS解决方案比下划线解决方案有两个优势:

  1. 它使用通常更快,更稳定的原生方法
  2. 它不会仅为所需的几种方法加载整个库

答案 1 :(得分:0)

您可以使用Object.keys和Array.forEach来实现您的需求。

&#13;
&#13;
var data = {
  "28-11": {
    "S1": {
      "M1": {
        "K1": 10,
        "K2": 12,
        "K3": 15
      },
      "M2": {
        "K1": 8,
        "K2": 6,
        "K3": 5
      }
    },
    "S2": {
      "M1": {
        "K1": 8,
        "K2": 6,
        "K3": 5
      },
      "M2": {
        "K1": 10,
        "K2": 12,
        "K3": 15
      }
    }
  }
};

var output = {};

//Iterate over Dates
Object.keys(data).forEach((date) => {
  var dateObj = data[date];
  output[date] = {};

  //Iterate over Shifts
  Object.keys(dateObj).forEach((shift) => {
    var shiftObj = dateObj[shift];

    //Iterate over machines
    Object.keys(shiftObj).forEach((machine) => {
      //Initialize if the machine is not already iterated earlier.
      output[date][machine] = output[date][machine] || {};
      Object.keys(shiftObj[machine]).forEach((keyValue) => {

        if (!output[date][machine][keyValue]) {
          output[date][machine][keyValue] = 0;
        }

        output[date][machine][keyValue] += shiftObj[machine][keyValue];

      });
    });
  });
});


console.log(output);
&#13;
&#13;
&#13;

答案 2 :(得分:0)

这是我的版本:

const data = {"28-11":{"S1":{"M1":{"K1":10,"K2":12,"K3":15},"M2":{"K1":8,"K2":6,"K3":5}},"S2":{"M1":{"K1":8,"K2":6,"K3":5},"M2":{"K1":10,"K2":12,"K3":15}}}};

var out = {};

Object.keys(data).forEach(date => 
    Object.keys(data[date]).forEach(shift => 
        Object.keys(data[date][shift]).forEach(machine => 
            Object.keys(data[date][shift][machine]).forEach(key => {
                if (out[date] === undefined) out[date] = {};
                if (out[date][machine] === undefined) out[date][machine] = {};
                if (out[date][machine][key] === undefined) out[date][machine][key] = 0;
                out[date][machine][key] += data[date][shift][machine][key];

            })
        )
   )
)
console.log(out)
return out;

答案 3 :(得分:0)

这是另一种可能性。

var data = {"28-11":{"S1":{"M1":{"K1":10,"K2":12,"K3":15},"M2":{"K1":8,"K2":6,"K3":5}},"S2":{"M1":{"K1":8,"K2":6,"K3":5},"M2":{"K1":10,"K2":12,"K3":15}}}};
    
    data = _.mapObject(data, function (days) {
      return _.map(days, function (day) {
        return _.reduce(day, function (acc, machine) {
          return _.extend({}, acc, _.mapObject(machine, function (keyVal, keyKey) {
            return (acc[keyKey] || 0) + keyVal;
          }));
        }, {});
      });
    });
    
    console.log(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Here's JSBin。

老实说,如果你想获得好地图并减少,我建议你浏览RxJS的this教程网页。你可以在它开始使用RxJS后立即退出,但它教授函数式编程,它教你映射过滤器并像老板一样减少。