对象从数组而不是硬代码中赋值
Posted
技术标签:
【中文标题】对象从数组而不是硬代码中赋值【英文标题】:Object Assign values from array rather than hard code 【发布时间】:2021-07-29 23:46:25 【问题描述】:我正在尝试按多个属性对数据进行分组并对它们的值求和。
这是我按照this question尝试的方法
我对这个问题进行了跟进:
const arr = ["shape":"square","color":"red","used":1,"instances":1,"shape":"square","color":"red","used":2,"instances":1,"shape":"circle","color":"blue","used":0,"instances":0,"shape":"square","color":"blue","used":4,"instances":4,"shape":"circle","color":"red","used":1,"instances":1,"shape":"circle","color":"red","used":1,"instances":0,"shape":"square","color":"blue","used":4,"instances":5,"shape":"square","color":"red","used":2,"instances":1];
const result = [...arr.reduce((r, o) =>
const key = o.shape + '-' + o.color;
const item = r.get(key) || Object.assign(, o,
used: 0,
instances: 0
);
item.used += o.used;
item.instances += o.instances;
return r.set(key, item);
, new Map).values()];
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
我想通过数值使其更易于重用。例如,我想要
const item = r.get(key) || Object.assign(, o,
used: 0,
instances: 0
);
item.used += o.used;
item.instances += o.instances;
部分特别是可重复使用的。
我得到了一个数组中的数值键:let gee = ['used', 'instances'];
我不确定如何将它与Object.assign
一起使用。我试着这样做:
const result = [...arr.reduce((r, o) =>
const key = o.shape + '-' + o.color;
// console.log(o);
const item = gee.forEach(v => o[v] += o[v]);
// const item = r.get(key) || Object.assign(, o,
// used: 0,
// instances: 0
// );
// item.used += o.used;
// item.instances += o.instances;
return r.set(key, item);
, new Map).values()];
但这不起作用。我如何在这段代码中使用数组:
const item = r.get(key) || Object.assign(, o,
used: 0,
instances: 0
);
item.used += o.used;
item.instances += o.instances;
【问题讨论】:
【参考方案1】:如果 Map
对象 has
是键,则循环遍历 totalKeys
并使用当前对象的数据递增累加器中的对象。如果是新的key
,则将该对象的副本添加到Map中
if (r.has(key))
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
else
r.set(key, ...o )
这是一个sn-p:
const arr = ["shape":"square","color":"red","used":1,"instances":1,"shape":"square","color":"red","used":2,"instances":1,"shape":"circle","color":"blue","used":0,"instances":0,"shape":"square","color":"blue","used":4,"instances":4,"shape":"circle","color":"red","used":1,"instances":1,"shape":"circle","color":"red","used":1,"instances":0,"shape":"square","color":"blue","used":4,"instances":5,"shape":"square","color":"red","used":2,"instances":1];
function groupSum(array, totalKeys)
const group = arr.reduce((r, o) =>
const key = o.shape + '-' + o.color;
if (r.has(key))
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
else
r.set(key, ...o )
return r;
, new Map);
return Array.from(group.values())
console.log(
groupSum(arr, ['used', 'instances'])
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
您可以通过提供一组键来分组,使其更加动态。使用由|
分隔的对象的值创建key
const key = groupKeys.map(k => o[k]).join("|");
if (r.has(key))
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
else
r.set(key, ...o )
这是一个sn-p:
const arr = ["shape":"square","color":"red","used":1,"instances":1,"shape":"square","color":"red","used":2,"instances":1,"shape":"circle","color":"blue","used":0,"instances":0,"shape":"square","color":"blue","used":4,"instances":4,"shape":"circle","color":"red","used":1,"instances":1,"shape":"circle","color":"red","used":1,"instances":0,"shape":"square","color":"blue","used":4,"instances":5,"shape":"square","color":"red","used":2,"instances":1];
function groupSum(array, groupKeys, totalKeys)
const group = arr.reduce((r, o) =>
const key = groupKeys.map(k => o[k]).join("|");
if (r.has(key))
const item = r.get(key)
totalKeys.forEach(k => item[k] += o[k])
else
r.set(key, ...o )
return r;
, new Map);
return Array.from(group.values())
console.log(
groupSum(arr, ['shape', 'color'], ['used', 'instances'])
)
【讨论】:
【参考方案2】:您也可以通过不使用 array.reduce() 与 map() 的组合来极大地简化数据集...而是通过使用 array.forEach() 循环遍历原始数组的所有元素来构建新数组。 )。
我添加了您对 gee 数组的使用作为您想要添加的数字字段的列表...包括确保它们存在于结果数组的每个对象上...无论它们是否存在于每个arr 中的先前对象。
const arr = [
"shape": "square",
"color": "red",
"used": 1,
"instances": 1
,
"shape": "square",
"color": "red",
"used": 2,
"instances": 1
,
"shape": "circle",
"color": "blue",
"used": 0,
"instances": 0
,
"shape": "square",
"color": "blue",
"used": 4,
"instances": 4
,
"shape": "circle",
"color": "red",
"used": 1,
"instances": 1
,
"shape": "circle",
"color": "red",
"used": 1,
"instances": 0,
"testProp": 1
,
"shape": "square",
"color": "blue",
"used": 4,
"instances": 5
,
"shape": "square",
"color": "red",
"used": 2,
"instances": 1
];
let gee = ['used', 'instances', 'testProp'];
let result = [];
arr.forEach((o) =>
// Setup TempSource since not all o may have all elements in gee
let tempSource = ;
gee.forEach((key) =>
if (o.hasOwnProperty(key))
tempSource[key] = o[key];
else
tempSource[key] = 0;
);
// Look to see if the result array already has an object with same shape/color
const matchingObject = result.find(element =>
let returnValue = true;
returnValue &= (element.shape == o.shape);
returnValue &= (element.color == o.color);
return returnValue;
);
if (matchingObject)
// Matching Object already exists... so increment values
gee.forEach((key) =>
matchingObject[key] += tempSource[key];
);
else
// Matching Object missing, so merge newObject and insert
let newObj = ;
Object.assign(newObj, o, tempSource);
result.push(newObj);
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
【讨论】:
【参考方案3】:也许这是一条路:
const arr = ["shape":"square","color":"red","used":1,"instances":1,"shape":"square","color":"red","used":2,"instances":1,"shape":"circle","color":"blue","used":0,"instances":0,"shape":"square","color":"blue","used":4,"instances":4,"shape":"circle","color":"red","used":1,"instances":1,"shape":"circle","color":"red","used":1,"instances":0,"shape":"square","color":"blue","used":4,"instances":5,"shape":"square","color":"red","used":2,"instances":1],
nums=["used","instances"]
function summationOn(ar,cnts) // cnts: add up counts on these properties
const grp=Object.keys(ar[0]).filter(k=>cnts.indexOf(k)<0) // grp: group over these
return Object.values(ar.reduce((a,c,t)=>
const k=grp.map(g=>c[g]).join("|");
if (a[k]) cnts.forEach(p=>a[k][p]+=c[p])
else a[k]=...c;
return a
,))
const res=summationOn(arr,nums);
console.log(res);
重写
与@adiga 类似,我现在希望在数组cnts
中给出“可数”属性。使用这个数组,我将输入数组ar
的第一个对象的所有其他属性收集到数组grp
中。这些是我将分组的属性。
【讨论】:
他们有一个他们想要求和的属性数组。let gee = ['used', 'instances']
。他们不想像t.used+=c.used
那样硬编码
啊 - 谢谢你告诉我。那么,如何识别求和的属性?!?
您可以发送一组属性来求和。循环遍历数组并动态获取属性。您甚至可以使用一组属性按["shape", "color"]
分组。检查我的答案中的 sn-ps以上是关于对象从数组而不是硬代码中赋值的主要内容,如果未能解决你的问题,请参考以下文章