如何从javascript中的对象计算新数据

时间:2016-10-06 13:13:41

标签: javascript arrays json object math

我有以下数据:

[ {
  "names" : [ "a3","printed","black" ],
  "value" : 15
}, {
  "names" : [ "a3","copied","black" ],
  "value" : 87
}, {
  "names" : [ "a3","printed","color","full" ],
  "value" : 37
}, {
  "names" : [ "a3","copied","color","single" ],
  "value" : 0
}, {
  "names" : [ "a3","copied","color","full" ],
  "value" : 44
}, {
  "names" : [ "a3","scanned" ],
  "value" : 288
}, {
  "names" : [ "total" ],
  "value" : 242142
}, {
  "names" : [ "scanned" ],
  "value" : 67411
}, {
  "names" : [ "copied","black" ],
  "value" : 79997
}, {
  "names" : [ "copied","full","color" ],
  "value" : 809
}, {
  "names" : [ "copied","single","color" ],
  "value" : 0
}, {
  "names" : [ "printed","two","color" ],
  "value" : 0
}, {
  "names" : [ "printed","black" ],
  "value" : 120665
}, {
  "names" : [ "printed","full","color" ],
  "value" : 40657
} ]

我尝试创建一些结构来组织数据,我可以看到对象之间的关系并计算新对象。 基本上我想要的是能够计算缺失的数据。 例如,我知道这些关系:

{
  "colors" : {
    "black" : "",
    "color" : [ "full", "two", "single" ]
  },
  "functions" : {
    "scanned" : "",
    "total" : [ "printed", "copied", "faxed" ]
  },
  "papers" : {
    "a3" : ""
  }
}

基于此,我想得到以下内容:

{
    "a3" : 183,
    "color" : 41466,
    "black" : 200662,
    "copied" : 80806,
    "printed" : 161322
}

我知道这一点,考虑到以下因素: a3 total仅由打印,复制和传真的功能组成,例如a3扫描值不在a3总值的计算范围内。

但我想不出任何想法如何使用JavaScript。 任何人都能指出我正确的方向吗?

3 个答案:

答案 0 :(得分:22)

基本上,此提案使用树来表示所需的值。

  1. names属性的正确分配生成排序模式。

  2. 迭代给定数据

    1. 获取a.names
    2. 的副本
    3. 排序names
    4. 测试relations.functions.total是否包含names的第一个元素,然后将'total'取消移动到名称。
    5. 迭代names并根据元素构建对象。
    6. value分配给对象中的value属性。
  3. 仅计算result.total分支的所有缺失值。

    1. 对所需物品的所有单个属性进行求和。
  4. 
    
    function calculateValues(o) {
        return Object.keys(o).reduce(function (r, k) {
            var v;
            if (k === 'value') {
                return r;
            }
            v = calculateValues(o[k]);
            if (o[k].value === null) {
                o[k].value = v;
            }
            values[k] = (values[k] || 0) + o[k].value;
            return r + o[k].value;
        }, 0);
    }
    
    var data = [{ names: ["a3", "printed", "black"], value: 15 }, { names: ["a3", "copied", "black"], value: 87 }, { names: ["a3", "printed", "color", "full"], value: 37 }, { names: ["a3", "copied", "color", "single"], value: 0 }, { names: ["a3", "copied", "color", "full"], value: 44 }, { names: ["a3", "scanned"], value: 288 }, { names: ["total"], value: 242142 }, { names: ["scanned"], value: 67411 }, { names: ["copied", "black"], value: 79997 }, { names: ["copied", "full", "color"], value: 809 }, { names: ["copied", "single", "color"], value: 0 }, { names: ["printed", "two", "color"], value: 0 }, { names: ["printed", "black"], value: 120665 }, { names: ["printed", "full", "color"], value: 40657 }],
        relations = { colors: { "black": "", color: ["full", "two", "single"] }, functions: { scanned: "", total: ["printed", "copied", "faxed"] }, papers: { "a3": "" } },
        priorities = ['functions', 'colors', 'papers'], // as long as keys of objects are not ordered
        order = {},
        result = {},
        values = {},
        i = 0;
    
    priorities.forEach(function (p) {
        Object.keys(relations[p]).forEach(function (k) {
            order[k] = ++i;
            Array.isArray(relations[p][k]) && relations[p][k].forEach(function (a) {
                order[a] = ++i;
            });
        });
    });
    
    data.forEach(function (a) {
        var names = a.names.slice();
        names.sort(function (a, b) {
            return (order[a] || 0) - (order[b] || 0);
        });
        if (relations.functions.total.indexOf(names[0]) !== -1) {
            names.unshift('total');
        }
        names.reduce(function (o, k) {
            return o[k] = o[k] || { value: null };
        }, result).value = a.value;
    });
    
    calculateValues(result.total);
    // calculateCount(result.scanned); 
    
    console.log(values);
    console.log(result);
    
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    
    
    

答案 1 :(得分:0)

以下是概念证明。它在CoffeeScript中。您可以使用js2.coffee轻松将其编译为JavaScript。另外,我已经包含了JS代码以供参考。 不确定这是否是你要找的。这可能不是最好的方法,但它可能会帮助你。一旦找到(找到),就可以设置你想要的第三种(obj3)方式。

###
THIS IS COFFEESCRIPT BELOW
###
Array::containsAny = (arr) ->
  @some (v) ->
    arr.indexOf(v) >= 0

obj1 = []
obj2 = {}
obj3 = {}
totalArr = []
colorArr = []
bl = null
scan = null
a3 = null

for k,v of obj2
  colObj = v if k is 'colors'
  funcObj = v if k is 'functions'
  paperObj = v if k is 'papers'
  if colObj isnt null
    for k,v of colObj
      colorArr = v if k is 'color'
      bl = k if k 'black'
  if funcObj isnt null
    for k,v of funcObj
      totalArr = v if k is 'total'
      scan = k if k is 'scanned'
  if paperObj isnt null
    for k,v of paperObj
      a3 = k if k is 'a3'
  return

for k,v of obj1
  names = v if k is 'names'
  val = v if k is 'value'
  foundBlack = names.containsAny(['black'])
  founda3 = names.containsAny(['a3'])
  foundColor = names.containsAny(colorArr)
  foundTotal = names.containsAny(TotalArr)
  return

var a3, bl, colObj, colorArr, foundBlack, foundColor, foundTotal, founda3, funcObj, k, names, obj1, obj2, obj3, paperObj, scan, totalArr, v, val;

Array.prototype.containsAny = function(arr) {
  return this.some(function(v) {
    return arr.indexOf(v) >= 0;
  });
};

//Your first array of objects
obj1 = [];

//your second object of objects
obj2 = {};

//declaring an empty object
obj3 = {};


totalArr = [];

colorArr = [];

bl = null;

scan = null;

a3 = null;

for (k in obj2) {
  v = obj2[k];
  if (k === 'colors') {
    colObj = v;
  }
  if (k === 'functions') {
    funcObj = v;
  }
  if (k === 'papers') {
    paperObj = v;
  }
  if (colObj !== null) {
    for (k in colObj) {
      v = colObj[k];
      if (k === 'color') {
        colorArr = v;
      }
      if (k('black')) {
        bl = k;
      }
    }
  }
  if (funcObj !== null) {
    for (k in funcObj) {
      v = funcObj[k];
      if (k === 'total') {
        totalArr = v;
      }
      if (k === 'scanned') {
        scan = k;
      }
    }
  }
  if (paperObj !== null) {
    for (k in paperObj) {
      v = paperObj[k];
      if (k === 'a3') {
        a3 = k;
      }
    }
  }
  return;
}

for (k in obj1) {
  v = obj1[k];
  if (k === 'names') {
    names = v;
  }
  if (k === 'value') {
    val = v;
  }
  foundBlack = names.containsAny(['black']);
  founda3 = names.containsAny(['a3']);
  foundColor = names.containsAny(colorArr);
  foundTotal = names.containsAny(TotalArr);
  return;
}

答案 2 :(得分:0)

您是否需要为每个value计算names?如果是,请尝试

var output = {};
for (var i in data) {
    for (var j in data[i].names) {
        var mark = data[i].names[j];
        output[mark] = (output[mark] || 0) + data[i].value;
    }
} 

https://jsfiddle.net/chukanov/0kctjwyv/