这可能是补救措施,但我不知道。我试过使用d3并与lodash一起玩以获得有效的解决方案,但没有得到任何结果。
我在JavaScript中有一个对象数组。如果[Selected]值为true,我想创建一个按[Version Name]分组的对象,该对象的计数为 distinct 个区域,每个版本的总数之和。例如对象...
[
{ Selcted: false, Version Name: "aaa", Zone: "11111", Value: 5 },
{ Selcted: false, Version Name: "aaa", Zone: "11111", Value: 10 },
{ Selcted: true, Version Name: "aaa", Zone: "11111", Value: 15 },
{ Selcted: true, Version Name: "aaa", Zone: "11111", Value: 20 },
{ Selcted: true, Version Name: "aaa", Zone: "22222", Value: 25 },
{ Selcted: true, Version Name: "bbb", Zone: "22222", Value: 30 },
{ Selcted: true, Version Name: "bbb", Zone: "22222", Value: 35 },
{ Selcted: true, Version Name: "bbb", Zone: "2222", Value: 40 }
]
应返回
的结果[
{ Version Name: "aaa", Zone Count: "2", Value Sum: 50 },
{ Version Name: "bbb", Zone Count: "1", Value Sum: 105 },
]
答案 0 :(得分:1)
这使用了我最喜欢的groupBy函数:)一旦获得了分组,您就可以进行另一个分组以获取区域计数,并进行归约以获取总和。
简而言之
const byName = groupBy(input.filter(it => it.Selcted), it => it['Version Name'])
const output = Object.keys(byName).map(name => {
const byZone = groupBy(byName[name], it => it.Zone)
const sum = byName[name].reduce((acc, it) => acc + it.Value, 0)
return {
'Version Name': name,
ZoneCount: Object.keys(byZone).length,
ValueSum: sum
}
})
别忘了,您需要在“版本名称”两边加上引号,才能将其用作键。
这是您的数据集的有效示例。
function groupBy(a, keyFunction) {
const groups = {};
a.forEach(function(el) {
const key = keyFunction(el);
if (key in groups === false) {
groups[key] = [];
}
groups[key].push(el);
});
return groups;
}
const input = [{
Selcted: false,
'Version Name': "aaa",
Zone: "11111",
Value: 5
},
{
Selcted: false,
'Version Name': "aaa",
Zone: "11111",
Value: 10
},
{
Selcted: true,
'Version Name': "aaa",
Zone: "11111",
Value: 15
},
{
Selcted: true,
'Version Name': "aaa",
Zone: "11111",
Value: 20
},
{
Selcted: true,
'Version Name': "aaa",
Zone: "22222",
Value: 25
},
{
Selcted: true,
'Version Name': "bbb",
Zone: "22222",
Value: 30
},
{
Selcted: true,
'Version Name': "bbb",
Zone: "22222",
Value: 35
},
{
Selcted: true,
'Version Name': "bbb",
Zone: "2222",
Value: 40
}
]
const byName = groupBy(input.filter(it => it.Selcted), it => it['Version Name'])
const output = Object.keys(byName).map(name => {
const byZone = groupBy(byName[name], it => it.Zone)
const sum = byName[name].reduce((acc, it) => acc + it.Value, 0)
return {
'Version Name': name,
ZoneCount: Object.keys(byZone).length,
ValueSum: sum
}
})
console.log(output)
答案 1 :(得分:1)
使用filter
来获取所需的物品后,您可以分两步进行操作,先进行reduce
,然后再进行map
let input = [
{ Selcted: false, "Version Name": "aaa", Zone: "11111", Value: 5 },
{ Selcted: false, "Version Name": "aaa", Zone: "11111", Value: 10 },
{ Selcted: true, "Version Name": "aaa", Zone: "11111", Value: 15 },
{ Selcted: true, "Version Name": "aaa", Zone: "11111", Value: 20 },
{ Selcted: true, "Version Name": "aaa", Zone: "22222", Value: 25 },
{ Selcted: true, "Version Name": "bbb", Zone: "22222", Value: 30 },
{ Selcted: true, "Version Name": "bbb", Zone: "22222", Value: 35 },
{ Selcted: true, "Version Name": "bbb", Zone: "2222", Value: 40 }
]
var result = input.filter(x => x.Selcted)
.reduce( (acc, curr) => {
let item = acc.find(x => x.version == curr["Version Name"]);
if(!item){
item = {version: curr["Version Name"], zones:{}}
acc.push(item);
}
item.zones[curr.Zone] = (item.zones[curr.Zone] || 0) + curr.Value
return acc;
},[])
.map(x => ({
"Version Name": x.version,
"Zone Count": Object.keys(x.zones).length,
"Value Sum": Object.values(x.zones).reduce( (a,b) => a+b ,0)
}))
console.log(result);
答案 2 :(得分:1)
您可以使用lodash并通过使用分组获得所需的计数
_
“ Seq”方法,用于链接lodash方法,_.groupBy
用于按"Version Name"
分组_.map
用于结果集_.uniqBy
用于计数不同的值,_.sumBy
用于求和Value
和_.value
用于获取带有对象作为结果集的数组。
var data = [{ Selected: false, "Version Name": "aaa", Zone: "11111", Value: 5 }, { Selected: false, "Version Name": "aaa", Zone: "11111", Value: 10 }, { Selected: true, "Version Name": "aaa", Zone: "11111", Value: 15 }, { Selected: true, "Version Name": "aaa", Zone: "11111", Value: 20 }, { Selected: true, "Version Name": "aaa", Zone: "22222", Value: 25 }, { Selected: true, "Version Name": "bbb", Zone: "22222", Value: 30 }, { Selected: true, "Version Name": "bbb", Zone: "22222", Value: 35 }, { Selected: true, "Version Name": "bbb", Zone: "22222", Value: 40 }],
result = _(data)
.groupBy('Version Name')
.map((array, key) => ({
"Version Name": key,
"Zone Count": _.uniqBy(array, 'Zone').length,
"Value Sum": _.sumBy(array, 'Value')
}))
.value();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
答案 3 :(得分:0)
假设您的数据数组名为arr
:
const summed = Object.values(
arr
.filter(x => x.Selected)
.reduce((acc, obj) => {
if (!acc[obj["Version Name"]) {
acc["Version Name"] = {
"Version Name": acc["Version Name"],
"Zones": new Set(),
"Value Sum": 0,
};
}
acc["Version Name"]["Value Sum"] += obj.Value;
acc["Version Name"].Zones.add(obj.Zone);
return acc;
})
).map(obj => {
return {
"Version Name": obj["Version Name"],
"Zone Count": obj.Zones.size,
"Value Sum": obj["Value Sum"],
};
});
首先,我们通过对版本名称进行哈希处理,筛选出未选中的对象,并通过版本名称获得不同的对象数组,对值进行聚合,使用Set跟踪不同的区域,然后使用Object.values
将哈希返回排列成一个数组。然后我们在其上进行映射,以获取每个Set的区域计数。
答案 4 :(得分:0)
您可以为此使用Array.reduce()和Set()来创建地图,然后在地图上Object.values()会给您想要的结果。尝试以下操作:
let arr = [ { Selected: false, VersionName: "aaa", Zone: "11111", Value: 5 }, { Selected: false, VersionName: "aaa", Zone: "11111", Value: 10 }, { Selected: true, VersionName: "aaa", Zone: "11111", Value: 15 }, { Selected: true, VersionName: "aaa", Zone: "11111", Value: 20 }, { Selected: true, VersionName: "aaa", Zone: "22222", Value: 25 }, { Selected: true, VersionName: "bbb", Zone: "22222", Value: 30 }, { Selected: true, VersionName: "bbb", Zone: "22222", Value: 35 }, { Selected: true, VersionName: "bbb", Zone: "2222", Value: 40 } ];
let set = new Set();
let result = Object.values(arr.reduce((a, curr)=>{
if(curr.Selected){
a[curr.VersionName] = a[curr.VersionName] || {versionName : curr.VersionName, ZoneCount : 0, ValueSum : 0} ;
if(!set.has(curr.Zone+"_"+curr.VersionName)){
a[curr.VersionName].ZoneCount += 1;
set.add(curr.Zone+"_"+curr.VersionName);
}
a[curr.VersionName].ValueSum += curr.Value;
}
return a;
},{}));
console.log(result);
答案 5 :(得分:0)
我认为最简单的解决方案是将reduce与filter一起使用
const selectedObjects = objects.filter((i) => i.Selected === true);
const results = selectedObjects.reduce((items, obj) => {
let item = items.find((i) => i.VersionName === obj["Version Name"]);
if (!item) {
const ZoneCount = selectedObjects
.filter((i) => i["Version Name"] === obj["Version Name"])
.reduce((zones, obj) => {
if (zones.indexOf(obj.Zone) === -1) {
zones.push(obj.Zone);
}
return zones;
}, []).length;
item = {
ValueSum: 0,
VersionName: obj["Version Name"],
ZoneCount
};
items.push(item);
}
item.ValueSum += obj.Value;
return items;
}, []);
console.log(results);
答案 6 :(得分:0)
首先过滤掉,然后分组,然后计算区域,因为我们需要在数组上使用heler函数:
Array.prototype.groupBy = function groupBy(key) {
const hash = {}, result = [];
for(const el of this) {
if(hash[ el[key] ]) {
hash[ el[key] ].push(el);
} else {
result.push({
key: el[key],
values: hash[ el[key] ] = [ el ],
});
}
}
return result;
};
Array.prototype.key = function(key) {
return this.map(el => el[key]);
};
Array.prototype.sum = function(key) {
return this.reduce((total, el) => total + (key ? el[key] : el), 0);
};
Array.prototype.unique = function() {
return [...new Set(this)];
};
这实际上是很多代码,但是现在我们可以使用它们来构建结果:
const result = array
.filter(el => el.Selected)
.groupBy("Version Name")
.map(({ key, values }) => ({
"Version Name": key,
"Value Sum": values.sum("Sum"),
"Zone Count":values.key("Zone").unique().length,
}));
答案 7 :(得分:0)
我觉得您可以使用一次reduce,使用2个hash(因为您希望在vanilla JS中使用它)来完成此操作,并且只遍历整个数组一次。似乎您想在一开始进行过滤,但是您可以执行一系列操作,例如
filter(...).map(...).reduce().continue().blabla(...)
(使用纯js或lodash,underscore ...等任何库)
现在
要么分离出逻辑,然后执行更易于理解和维护的更整洁的操作(例如:Nina Scholz's answer中有一个)
或者,仅使用reduce(或简单的for循环)遍历它一次并执行所有必要的操作,并尝试避免一系列遍历,而是像散列(或任何合适的方法)那样使用更多的内存来对其进行缓存。
这是我为此创建的示例
let input = [{ Selected: false, "Version Name": "aaa", Zone: "11111", Value: 5 }, { Selected: false, "Version Name": "aaa", Zone: "11111", Value: 10 }, { Selected: true, "Version Name": "aaa", Zone: "11111", Value: 15 }, { Selected: true, "Version Name": "aaa", Zone: "11111", Value: 20 }, { Selected: true, "Version Name": "aaa", Zone: "22222", Value: 25 }, { Selected: true, "Version Name": "bbb", Zone: "22222", Value: 30 }, { Selected: true, "Version Name": "bbb", Zone: "22222", Value: 35 }, { Selected: true, "Version Name": "bbb", Zone: "22222", Value: 40 }],
vn = "Version Name", vs = "Value Sum", zc = "Zone Count", //Target Keys
{res} = input.reduce(({res={}, hash={}}, e) => {
if(e.Selected) {
let vrsn = e[vn],
vrsnGrp = (hash[vrsn] = hash[vrsn] || {});
res[vrsn] = (res[vrsn] || {[vn]: vrsn, [vs]:0, [zc]: 0});
res[vrsn][vs] += e.Value;
res[vrsn][zc] += !vrsnGrp[e.Zone];
vrsnGrp[e.Zone] = true;
}
return {res, hash};
}, {});
console.log(Object.values(res));
.as-console-wrapper { max-height: 100% !important; top: 0; }
它将执行所有必要的操作(过滤,分组等),但仅遍历输入数组一次,它将仅使用一个额外的哈希(因为res
也是此处的哈希)。 / p>
答案 8 :(得分:0)
let campos = ["classificacao", "count_tables"];
let conteudo = mysql_information_schema[cliente][projeto][dbName].conteudo;
let count = {};
conteudo.forEach( (tabela)=> { //agrupa dentro de count
count[tabela.classificacao] = count[tabela.classificacao] > 0 ? count[tabela.classificacao] + 1 : 1 ;
});
//converte o objeto para o padrão do array object da view
conteudo = Object.keys(count).map( (key)=>{return {classificacao: key, count_tables: count[key]} } );