【问题标题】:Merging javascript objects合并javascript对象
【发布时间】:2015-11-19 22:53:01
【问题描述】:

希望合并两个对象。但是,当两个对象中存在具有相同值的属性“日期”时,其他属性(tag1 和 tag2)将被合并到同一日期下。

示例输入

var myVar1 = [
{
"date": "2015-07-16",
  "tag1": 35.34},
{
"date": "2015-07-18",
  "tag1": 34.12}
  ];

var myVar2 = [
{
"date": "2015-07-16",
  "tag2": 45.34},
{
"date": "2015-07-17",
  "tag2": 44.12}
  ];

期望的输出

mergedVar = [
{
"date": "2015-07-16",
  "tag1": 35.34,
  "tag2": 45.34},
{
"date": "2015-07-17",
  "tag2": 44.12},
{
"date": "2015-07-18",
  "tag1": 34.12}
  ];

【问题讨论】:

  • 不要认真使用这个实现,但我玩得很开心golfing这个:function merge(G,o,l,f,i,n,g,I,s,F,u,N){u={};N=[];for(o=0,l=G.length;o<l;o++)for(f=0,i=(n=G[o]).length;f<i;f++){g=n[f];I=(u[F='#'+g.date]||(N.push(I={}),u[F]=I));for(s in g)Object.prototype.hasOwnProperty.call(g,s)&&(I[s]=g[s])}return N}用法:var mergedVar = merge([myVar1, myVar2]);
  • @icktoofay 好的。我不会(阅读不能)使用该实现。我是 JavaScript 新手,在这里可以使用很少的帮助。问题是正确的实施方式是什么?谢谢。

标签: javascript merge javascript-objects


【解决方案1】:

我发表评论的想法是其他人会发表更严肃的答案,但由于没有人出现,我想我会描述你如何认真地去做。

首先,您必须知道如何将一个对象合并到另一个对象中。这不是太难,但你必须知道如何使用for-in,这不是经常教的,而且包含hasOwnProperty检查通常是个好主意,它甚至不经常教:

function mergeObjectInto(source, target) {
    for(var property in source) {
        if(Object.prototype.hasOwnProperty.call(source, property)) {
            target[property] = source[property];
        }
    }
}

本质上,这会枚举源的所有属性。如果该属性是对象的自己的属性——也就是说,它不是从其原型继承的东西——我们将该属性复制到目标。

现在,要对您想要执行的操作进行建模,我们可以将其分解为更简单的操作:给定一个现有数组,将另一个对象放入该数组中,并在必要时合并。一个简单的实现可能如下所示:

function mergeObjectIntoArray(existingArray, newObject) {
    // Search for an already-existing object in the array that shares the same
    // value for the `date' property.
    var correspondingExistingObject = null;
    for(var index = 0, length = existingArray.length; index < length; index++) {
        if(existingArray[index].date === newObject.date) {
            correspondingExistingObject = existingArray[index];
            break;
        }
    }
    if(correspondingExistingObject !== null) {
        // If we found an existing object that corresponds to our new object, just
        // merge any new properties in rather than adding a new item to the array.
        mergeObjectInto(newObject, correspondingExistingObject);
    }else{
        // Otherwise, bite the bullet and add the new object since there's nothing
        // we can usefully merge into.
        existingArray.push(newObject);
    }
}

然后您可以通过在循环中调用此函数来实现您想要的那种合并操作。但是如果你算出来,那将有二次时间,如果这必须处理大量数据项,这将是一个问题。碰巧,有一种方法可以解决它。如果我们将项目排序为一个由date 属性作为键的类似哈希表的结构,我们可以在常数时间内检查我们是否有一个具有该日期的对象,如果有,则合并到其中;否则,添加它。这导致整个算法的线性时间非常合理。

一个复杂的问题是,直到最近使用 ECMAScript 6,JavaScript 还没有真正拥有真正的“哈希表”。我们拥有的最接近的东西是对象,它只能有字符串键。这对我们有用,但我们确实需要谨慎行事:无论好坏,浏览器供应商都创建了一些具有特殊意义的属性名称,例如__proto__,我们真的不想踩到它们,所以我们'将为我们的键添加一些字符,以防止与内置名称发生任何冲突。为此,我选择了#。 (# 是一个哈希,它是一个哈希表。)

在代码中,这是如何实现的,这次函数采用整个项目数组并合并所有具有重复 date 属性值的对象:

function mergeDuplicateObjectsInArray(array) {
    var result = [];
    var objectsByDate = {};
    for(var index = 0, length = array.length; index < length; index++) {
        var object = array[index];
        var hashKey = '#' + object.date;
        var mergeTarget;
        if(Object.prototype.hasOwnProperty.call(objectsByDate, hashKey)) {
            // Already have an object by that date; we ought to merge into that.
            mergeObjectInto(object, objectsByDate[object.date]);
        }else{
            // No object by that date yet; we'll be the first.
            result.push(object);
            objectsByDate[object.date] = object;
        }
    }
    return result;
}

这仍然遗漏了最后一件事:它只是合并单个数组中的对象,而不是两个不同的数组。但是如果你用两个数组的对象创建了一个数组,它会做你想做的事,例如myVar1.concat(myVar2)。在任何情况下,您还可以修改其中的for 循环以循环遍历数组数组,然后循环遍历这些数组中的对象,这就是我打高尔夫球的版本所做的。 Golfed 版本的另一个区别是 Golfed 版本避免修改原始数组或对象,这将是对未混淆版本的相对简单的修改:制作副本,只需合并到一个空对象中。

希望这可以解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-29
    • 2020-09-12
    • 2016-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多