对象从数组而不是硬代码中赋值

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

以上是关于对象从数组而不是硬代码中赋值的主要内容,如果未能解决你的问题,请参考以下文章

ES6之解构赋值

es6 解构赋值

3-变量的解构赋值

为什么我可以使用数组破坏性赋值给一个引用,而不是对象破坏性赋值?[重复]

ES 6 : 变量的解构赋值

如何从 API 声明数组来代替硬编码数组?