【问题标题】:Merge two javascript objects adding values of common properties合并两个添加公共属性值的 javascript 对象
【发布时间】:2012-02-07 10:54:06
【问题描述】:

我有两个或多个 javascript 对象。我想合并它们,添加公共属性的值,然后按值的降序对它们进行排序。

例如

var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}

var c = merge(a,b)

c 应该是这样的:

c = {
fr: 24,
en: 13,
in:9,
br:8
} 

即两个对象都合并,添加公共键的值,然后对键进行排序。

这是我尝试过的:

var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}
c = {}

// copy common values and all values of a to c
for(var k in a){
  if(typeof b[k] != 'undefined'){  
    c[k] = a[k] + b[k]  
  }
  else{ c[k] = a[k]}
}

// copy remaining values of b (which were not common)
for(var k in b){
 if(typeof c[k]== 'undefined'){
  c[k] = b[k]
 }
} 

// Create a object array for sorting
var arr = [];

for(var k in c){
 arr.push({lang:k,count:c[k]})
}

// Sort object array
arr.sort(function(a, b) {
   return b.count - a.count;
})

但我不认为它好。这么多循环:(如果有人能提供一个不那么混乱和好的代码,那就太好了。

【问题讨论】:

  • @Dogbert 到目前为止,我在这里,pastebin.com/VQehhcri
  • 普通对象不排序。你需要一个数组来实现排序。
  • 以下答案都不起作用,但我找到了一种方法,但我认为它不好。请调查并优化代码。这是粘贴箱。 pastebin.com/nEKB7zAc
  • @Jashwant 你的排序代码没问题,只要 porpoerties 是数字

标签: javascript jquery json


【解决方案1】:

在 ES2015+ 中,对象属性 是有序的(首先按数字键升序,然后按非数字键的插入顺序)。如果您使用指定了迭代顺序的方法之一(如Object.getOwnPropertyNames),规范会保证这一点。

在 ES2020+ 中,以前未指定枚举顺序的方法are now specified(尽管环境已经遵循它很久了)。

但您必须确保所有属性都不是数字的(否则,无论插入顺序如何,它们都会在非数字属性之前出现)。

使用reduce 迭代每个对象,并在累加器上创建或添加相同的属性。然后,sort 对象的条目,并使用Object.fromEntries 将其转换为具有排序属性的对象。不需要 jQuery:

var a = {en : 5,fr: 3,in: 9}
var b = {en: 8,fr: 21,br: 8}
console.log(merge(a, b));

function merge(...objects) {
  const merged = objects.reduce((a, obj) => {
    Object.entries(obj).forEach(([key, val]) => {
      a[key] = (a[key] || 0) + val;
    });
    return a;
  }, {});
  return Object.fromEntries(
    Object.entries(merged).sort(
      (a, b) => b[1] - a[1]
    )
  );
}

【讨论】:

    【解决方案2】:

    无法对对象的属性进行排序,但可以对数组进行排序:

    var merged = $.extend({}, a);
    for (var prop in b) {
        if (merged[prop]) merged[prop] += b[prop];
        else merged[prop] = b[prop];
    }
    // Returning merged at this point will give you a merged object with properties summed, but not ordered.
    var properties = [];
    for (var prop in merged) {
        properties.push({
            name: prop,
            value: merged[prop]
        });
    }
    return properties.sort(function(nvp1, nvp2) {
        return nvp1.value - nvp2.value;
    });
    

    【讨论】:

    • 我已将 foreach 更改为 for 并将 name= prop 更改为 name:prop,但它仍然返回错误 :(
    • 像魅力一样工作:) 我没有得到代码,但这就是我所说的不那么混乱的代码。这里发生了什么事 ?返回 nvp1.value == nvp2.value ? 0:nvp1.value > nvp2.value? 1:-1;
    • @Jashwant 我已将该行更新为更简单:)。但是在上面它使用条件运算符?来检查值是否相等,如果相等则返回0,否则如果value1大于value2则返回1,否则返回-1。
    • 您的期望是获得对象,但您使用此解决方案获得数组,
    • @PravatMaskey 无法对对象的属性进行“排序”,但是您可以对数组进行排序。
    【解决方案3】:

    编辑 - 我修改了脚本,如果它们是相同类型的,这会合并属性:数字相加,字符串连接,对象递归合并。我没有包括排序,因为(引用这个答案Sorting JavaScript Object by property value

    JavaScript 对象根据定义是无序的(参见 ECMAScript 语言规范,第 8.6 节)。语言规范 甚至不保证,如果你迭代一个 连续两次对象,它们会以相同的顺序出现 第二次。

    如果您需要订购商品,请使用数组和 Array.prototype.sort 方法。

    function is_object(mixed_var) {
        if (Object.prototype.toString.call(mixed_var) === '[object Array]') {
            return false;
        }
        return mixed_var !== null && typeof mixed_var == 'object';
    }
    
    function merge(a, b) {
        var cache = {};
        cache = unpackObject(a, cache);
        cache = unpackObject(b, cache);
        return cache;
    
    
    }
    
    function unpackObject(a, cache) {
        for (prop in a) {
            if (a.hasOwnProperty(prop)) {
                if (cache[prop] === undefined) {
                    cache[prop] = a[prop];
                } else {
                    if (typeof cache[prop] === typeof a[prop]) {
                        if (is_object(a[prop])) {
                            cache[prop] = merge(cache[prop], a[prop]);
                        } else {
                            cache[prop] += a[prop];
                        }
                    }
                }
            }
        }
        return cache;
    }
    
    var a = {
        en: 5,
        fr: 3,
        in : 9,
        lang: "js",
        object: {nestedProp: 6}
    
    }
    var b = {
        en: 8,
        fr: 21,
        br: 8,
        lang: "en",
        object: {nestedProp: 1, unique: "myne"}
    }
    
    var c = merge(a, b);
    

    在这里摆弄http://jsfiddle.net/vyFN8/1/

    【讨论】:

    • @Jashwant 我更新了我的答案,您不能保证排序属性会按该顺序返回它们。
    • 是的,我已经检查过在 stackoverflow 的其他帖子上无法对对象进行排序。但是我们可以为它们创建对象数组。顺便说一句,您的解决方案既干净又强大。请添加代码进行排序,以便我可以将其标记为答案。
    • @Jashwant 只要你的属性是数字,你的排序算法就可以了
    • 你的回答太棒了
    【解决方案4】:

    这是我的尝试,它对嵌套对象是递归的 - https://gist.github.com/greenafrican/19bbed3d8baceb0a15fd

    // Requires jQuery
    // Merge nested objects and if the properties are numbers then add them together, else
    // fallback to jQuery.extend() result
    
    function mergeObjectsAdd(firstObject, secondObject) {
        var result = $.extend(true, {}, firstObject, secondObject);
        for (var k in result) {
            if ("object" === typeof result[k]) {
                firstObject[k] = firstObject[k] || {};
                secondObject[k] = secondObject[k] || {};
                result[k] = mergeObjectsAdd(firstObject[k], secondObject[k]);
            } else {
                firstObject[k] = firstObject[k] || 0;
                secondObject[k] = secondObject[k] || 0;
                result[k] = ("number" === typeof firstObject[k] && "number" === typeof secondObject[k]) ? (firstObject[k] + secondObject[k]) : result[k];
            }
        }
        return result;
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-16
      • 2014-03-10
      • 2021-03-20
      • 1970-01-01
      • 1970-01-01
      • 2020-07-23
      • 2016-10-29
      • 2018-03-13
      • 1970-01-01
      相关资源
      最近更新 更多