如何用相同的键求和值并返回一个对象?

时间:2018-08-08 11:53:03

标签: javascript arrays object

我试图根据选定的键对对象值求和,这些键在数组的每个对象中都可用。我的问题是如何处理percentage rate。在下面的代码示例中,satisfaction_rate应该具有48

我的输出应该是:

{ 'students' : 87, 'books': 32, 'satisfaction_rate': 48 }

const myData = [
  {
  'students' : 30,
  'books': 10,
  'satisfaction_rate': "60%",
  'returning_students': 14
  }, {
'students' : 25,
'books': 8,
'satisfaction_rate': "45%",
'returning_students': 14
  }, {
'students' : 32,
'books': 14,
'satisfaction_rate': "39%",
'returning_students': 19
  }
];


const keysToConsider = ['students', 'books', 'satisfaction_rate'];

function getSumOrAvgValuesOfKeys(data){
      const obj = {};
      let val = 0;
      keysToConsider.forEach(el => {
        data.forEach(element => {
          if (typeof(element[el] === 'string')) {
            val += parseInt(element[el], 10);
          } else {
            val += element[el];
          }
      });
        obj[el] = val;
        // Reset value
        val = 0;
    });
    return obj;
  }
  
console.log(getSumOrAvgValuesOfKeys(myData));

5 个答案:

答案 0 :(得分:5)

您可以使用reduce方法,然后在最后一次迭代中为值是字符串类型的每个元素计算平均值。

const myData = [{"students":30,"books":10,"satisfaction_rate":"60%","returning_students":14},{"students":25,"books":8,"satisfaction_rate":"45%","returning_students":14},{"students":32,"books":14,"satisfaction_rate":"39%","returning_students":19}]

const keys = ['students', 'books', 'satisfaction_rate'];

const result = myData.reduce((r, e, i, a) => {
  keys.forEach(k => r[k] = (r[k] || 0) + parseInt(e[k]));
  if(!a[i + 1]) Object.keys(e)
    .filter(k => typeof e[k] == 'string')
    .forEach(k => r[k] /= myData.length)
  return r;
}, {})

console.log(result)

答案 1 :(得分:1)

您可能还有另一个要对键进行平均的数组,在准备求和结果之后,您只能计算这些键的平均值。

const myData = [{
  'students': 30,
  'books': 10,
  'satisfaction_rate': "60%",
  'returning_students': 14
}, {
  'students': 25,
  'books': 8,
  'satisfaction_rate': "45%",
  'returning_students': 14
}, {
  'students': 32,
  'books': 14,
  'satisfaction_rate': "39%",
  'returning_students': 19
}];


const keysToConsider = ['students', 'books', 'satisfaction_rate'];
let keysWithPercent = ['satisfaction_rate'];

const summed = myData.reduce((result, item) => {
  keysToConsider.forEach(k => {
    if (!result[k]) {
      result[k] = 0;
    }
    
    let v = parseInt(item[k], 10);
    result[k] += v;
  });
  
  return result;
}, {});

keysWithPercent.forEach(k => {
  summed[k] = summed[k] / myData.length;
})

console.log(summed);

答案 2 :(得分:1)

您可以通过采用以前的值或默认值来减少对象。对于百分比值,请用三分之一进行求和。

var data = [{ students: 30, books: 10, satisfaction_rate: "60%", returning_students: 14 }, { students: 25, books: 8, satisfaction_rate: "45%", returning_students: 14 }, { students: 32, books: 14, satisfaction_rate: "39%", returning_students: 19 }],
    result = data.reduce((r, { students, books, satisfaction_rate }, _, a) => ({
        students: (students || 0) + students,
        books: (r.books || 0) + books,
        satisfaction_rate: (r.satisfaction_rate || 0) + satisfaction_rate.slice(0, -1) / a.length
    }), {});
      
console.log(result);

带有动态键列表

var data = [{ students: 30, books: 10, satisfaction_rate: "60%", returning_students: 14 }, { students: 25, books: 8, satisfaction_rate: "45%", returning_students: 14 }, { students: 32, books: 14, satisfaction_rate: "39%", returning_students: 19 }],
    keys = ['students', 'books', 'satisfaction_rate'],
    result = data.reduce((r, o, _, a) => 
        Object.assign(
            ...keys.map(k =>
                ({ [k]: (r[k] || 0) + (o[k].toString().endsWith('%')
                    ? o[k].slice(0, -1) / a.length
                    : o[k])
                }))
        ),
        {}
    );
      
console.log(result);

答案 3 :(得分:0)

恕我直言,您可以尝试使用reduce完成以下操作:

var myData = [{ students: 30, books: 10, satisfaction_rate: "60%", returning_students: 14 }, { students: 25, books: 8, satisfaction_rate: "45%", returning_students: 14 }, { students: 32, books: 14, satisfaction_rate: "39%", returning_students: 19 }]

var result = myData.reduce((accum, { students, books, satisfaction_rate }, idx, arr) => {
    accum["students"] ? (accum["students"] += students) : (accum["students"] = students);
    accum["books"] ? (accum["books"] += books) : (accum["books"] = books);
    accum["satisfaction_rate"] ? (accum["satisfaction_rate"] += parseInt(satisfaction_rate)) : (accum["satisfaction_rate"] = parseInt(satisfaction_rate));
    if (idx === arr.length - 1) {
      accum["satisfaction_rate"] = accum["satisfaction_rate"] / arr.length
    }
return accum;
}, {});

console.log(result);

答案 4 :(得分:0)

更通用的解决方案是指定您要如何减少 keysToConsider对象中的每个键。您可以使用SUM,AVG,MIN,MAX甚至是标准偏差等更复杂的参数来减少它们。

在这种情况下,我会将您的keysToConsider更改为对象而不是数组:

const myData = [{
    'students': 30,
    'books': 10,
    'satisfaction_rate': "60%",
    'returning_students': 14
}, {
    'students': 25,
    'books': 8,
    'satisfaction_rate': "45%",
    'returning_students': 14
}, {
    'students': 32,
    'books': 14,
    'satisfaction_rate': "39%",
    'returning_students': 19
}];

keysToConsider = {
    'students': sum,
    'books': sum,
    'satisfaction_rate': avg
}

function reduceValuesOfKeys(data) {
    const obj = {};
    let val = 0;
    for (var p in keysToConsider) {
        var reduce = keysToConsider[p];
        obj[p] = reduce(data, p);
    }
    return obj;
}

function sum(data, property) {
    var val = 0;
    data.forEach(element => {
        if (typeof(element[property] === 'string')) {
            val += parseInt(element[property], 10);
        } else {
            val += element[property];
        }
    });
    return val;
}

function avg(data, property) {
    var val = 0;
    data.forEach(element => {
        if (typeof(element[property] === 'string')) {
            val += parseInt(element[property], 10);
        } else {
            val += element[property];
        }
    });
    return val / data.length;
}

console.log(reduceValuesOfKeys(myData));

如果将来需要添加其他reduce函数,会更容易。