我有以下数据:
[ {
"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。 任何人都能指出我正确的方向吗?
答案 0 :(得分:22)
基本上,此提案使用树来表示所需的值。
为names
属性的正确分配生成排序模式。
迭代给定数据
a.names
。names
。relations.functions.total
是否包含names
的第一个元素,然后将'total'
取消移动到名称。names
并根据元素构建对象。value
分配给对象中的value
属性。仅计算result.total
分支的所有缺失值。
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;
}
}