代码之家  ›  专栏  ›  技术社区  ›  Fares K. A.

JavaScript:对具有相似属性的对象进行分组

  •  2
  • Fares K. A.  · 技术社区  · 10 年前

    我有一个JavaScript对象数组,看起来像这样。

    [ { name: "A", value: 50 },
      { name: "B", value: 20 }, 
      { name: "C", value: 30 }, 
      { name: "A", value: 40 }, 
      { name: "A", value: 50 }, 
      { name: "B", value: 70 }, 
      { name: "A", value: 10 }, 
      { name: "C", value: 50 } ]
    

    我想循环遍历这个数组,删除任何同名的重复对象,同时将它们的值加在一起。基本术语:

    [ { name: "A", value: 200 },
      { name: "B", value: 90  }, 
      { name: "C", value: 80  } ]
    

    我有一个想法,伪代码:

    for each object Obj in array A
        current = Obj
        for(i = (Obj's index + 1); i < A.length; i++)
            if(A[i].name = Obj.name) 
                Obj.value += A[i].value
                delete A[i]
            endif
        endfor
    endfor
    

    我觉得这样效率很低。有什么更好的办法吗?

    6 回复  |  直到 10 年前
        1
  •  3
  •   TAGraves    10 年前

    我将使用一个临时对象作为中间状态,然后基于该对象创建一个新数组:

    var arr = [ { name: "A", value: 50 },
      { name: "B", value: 20 }, 
      { name: "C", value: 30 }, 
      { name: "A", value: 40 }, 
      { name: "A", value: 50 }, 
      { name: "B", value: 70 }, 
      { name: "A", value: 10 }, 
      { name: "C", value: 50 } ];
    
    var tempObj = arr.reduce(function (newObj, obj) {
        if (newObj[obj.name]) {
            newObj[obj.name] += obj.value;
        } else {
            newObj[obj.name] = obj.value;
        }
        return newObj;
    }, {});
    
    console.log(tempObj);
    
    var result = [];
    
    for (var i in tempObj) {
        result.push({
            name: i,
            value: tempObj[i]
        });
    }
    
    console.log(result);
        2
  •  1
  •   Tomasz Pluskiewicz    10 年前

    您可以使用 reduce function .

    注意,为了简单起见,总和被收集为一个关联数组(按 name )然后检索值以匹配预期结果。

    var arr = [ { name: "A", value: 50 },
      { name: "B", value: 20 }, 
      { name: "C", value: 30 }, 
      { name: "A", value: 40 }, 
      { name: "A", value: 50 }, 
      { name: "B", value: 70 }, 
      { name: "A", value: 10 }, 
      { name: "C", value: 50 } ];
    
    var sums = arr.reduce(function (acc, curr) { 
      if(acc[curr.name]) {
        acc[curr.name].value += curr.value;
      } else {
        acc[curr.name] = curr;
      }
      
      return acc;
    }, {});
    
    var res = Object.keys(sums).map(function (key) {
        return sums[key];
    });
    
    console.log(res);
        3
  •  1
  •   Nenad Vracar    10 年前

    你可以用 forEach() 循环和 thisArg 参数

    var data = [ { name: "A", value: 50 },
      { name: "B", value: 20 }, 
      { name: "C", value: 30 }, 
      { name: "A", value: 40 }, 
      { name: "A", value: 50 }, 
      { name: "B", value: 70 }, 
      { name: "A", value: 10 }, 
      { name: "C", value: 50 } ];
      
    var result = [];
    data.forEach(function(e) {
      if (!this[e.name]) {
        this[e.name] = e;
        result.push(this[e.name]);
      } else {
        this[e.name].value += e.value;
      }
    }, {});
    
    console.log(result)
        4
  •  0
  •   Patrick Barr    10 年前

    您可以创建一个临时的“关联数组”并遍历对象数组,如

    var temp = [];
    for(var i = 0; i < A.length; i++) {
        temp[A[i].name] += A[i].value;
    }
    A = temp;
    

    如果你想继续 A 作为一个实际数组,然后查看@TAGraves答案,以获取将其转换为实际数组所需的额外位。

        5
  •  0
  •   Tomasz Lewowski    10 年前

    你在找 reduce 和基于对象的索引:

    var arr = [ { name: "A", value: 50 },
      { name: "B", value: 20 }, 
      { name: "C", value: 30 }, 
      { name: "A", value: 40 }, 
      { name: "A", value: 50 }, 
      { name: "B", value: 70 }, 
      { name: "A", value: 10 }, 
      { name: "C", value: 50 } ]
    
    var accumulated = arr.reduce(function(accumulator, element) {
         var currentValue = accumulator[element.name];
         if(currentValue !== undefined) {
             accumulator[element.name] = currentValue + element.value;
         } else {
             accumulator[element.name] = element.value;
         }
         return accumulator;
    }, {})
    
    var result = Object.keys(accumulated).map(function(k) {return {name: k, value: accumulated[k]}})
    console.log(result)
        6
  •  -1
  •   Thomas    10 年前

    这是什么语言?这不是JS。

    在JS中,我会这样写:

    array = array.filter(function(item){
        //check wether there's already an cached item for this name
        if(item.name in this){
            //then add the value to the cached item
            this[item.name].value += item.value;
            //and remove the current item from the result
            return false;
        }else{
            //otherwise cache this item
            this[item.name] = item;
            //and keep it in the result
            return true;
        }
    }, {/* abusing `this` as a cache */});