使用下划线的“差”的方法的对象的阵列(using underscore's “differe

2019-06-18 17:27发布

_.difference([], [])

当我具有像原始类型数据这种方法工作得很好

var a = [1,2,3,4];
var b = [2,5,6];

_.difference(a,b)调用返回[1,3,4]

但如果我使用的物体,像

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];

似乎不工作

Answer 1:

原因很简单,用相同的内容,对象不是同一对象如

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}]; 
a.indexOf({'id':1, 'value':10})

它不会返回0,但-1,因为我们正在寻找一个不同的对象

看到源代码http://underscorejs.org/underscore.js , _.difference使用_.contains

_.difference = function(array) {
  var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
  return _.filter(array, function(value){ return !_.contains(rest, value); });
};

_.contains最终使用indexOf因此,除非它们指向同一个对象会找不到对象。

您可以提高下划线_.contains通过所有项目循环和调用回调比较,你应该能够传递给差或包含功能或者您可以检查这个版本,其中包含改进方法



Answer 2:

试试这个关于大小寻找对象的数组的区别:

var test = [{a: 1},{b: 2}];
var test2 = [{a: 1}];

_.filter(test, function(obj){ return !_.findWhere(test2, obj); });


Answer 3:

虽然接受的答案是正确的,而其他的答案给出好的想法很好,没有那是很容易用下划线实施附加选项。

该解决方案依赖于具有唯一的ID每个对象上,但在许多情况下,这是真实的,你可以得到对象的两个数组在短短的两行代码的区别。

使用下划线的“勇气”的方法,可以快速构建你的源集和目标集中的所有的ID的数组。 从那里,所有的下划线的排列方法将工作,差异,工会,路口等...

手术后,实在是小巫见大巫获得从源列表,你的愿望的对象列表。 下面是一个例子:

详细:

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];

var arr1 = _.pluck(a, "id");
var arr2 = _.pluck(b, "id");
var diff = _.difference(arr1, arr2);
var result = _.filter(a, function(obj) { return diff.indexOf(obj.id) >= 0; });

或者,更简洁:

var diff = _.difference(_.pluck(a, "id"), _.pluck(b, "id"));
var result = _.filter(a, function(obj) { return diff.indexOf(obj.id) >= 0; });

当然,这个同样的技术可以被扩展用于任意的阵列方法中使用。



Answer 4:

实际上,我可以想像,我宁愿使用@不是别的东西kontr0l办法的情况下,但你要明白,这种做法是二次的,所以基本上这个代码是幼稚的方法的抽象 - 通过所有的值在两个数组迭代。

有办法比二次更好,我不会在这里使用任何大O符号,但这里有两个主要的方法,两者都优于天真之一:

  • 通过阵列中的一个迭代,并使用二进制搜索以排序第二阵列检查是否存在。
  • 把值放入集/散列/字典/你的名字。

作为it've已经述及,第一种方法可以,如果你重新实现标准被采纳为对象difference方法使用的一些更灵活的模拟indexOf方法。

随着第二种方法,我们可以用,作为Feb'2015,只有现代浏览器都支持的事实撞到墙上设置 。 如在javascript散列(当然,对象),它们只能有字符串型键,所以首先援引作为密钥的任何对象768,16经由被转换toString方法。 所以,我们需要提供一些=> correspondece。 在大多数情况下,实际上是非常简单的,例如,您的具体的例子这样的对应可以只是String(obj.id)

有了这样的对应,我们还可以使用以下lodas / undercore方法:

var idsA = _.pluck(a, 'id');
var idsB = _.pluck(b, 'id');

// actually here we can stop in some cases, because 
// quite often we need to identify object, but not the object itself - 
// for instance to send some ids through remote API.
var intersect = _.intersection(idsA, idsB);

//to be 100% sure you get the idea, here we assume that object having equal ids are treated as equal, so does not really matter which of arrays we'll iterate:

var dictA = _.object(idsA, a); // now we can find a by id faster then with _.find
var intersectObj = intersect.map(function(id) {return dictA[id})

但承认买稍微严格的限制 - 我们可以在我们设定的对象,我们可以建立甚至比较有效的算法,自然数之间建立对应关系,即我们所有的IDS都是非负整数 - 我们可以用更高效的算法。

关键是要落实引入两个辅助阵列这样设置:

var naturalSet = function (arr) {
    var sparse = [];
    var dense = [];

    var contains = function (i) {
        var res = sparse[i] < dense.length && dense[sparse[i]] == i;
        return res;
    }

    var add = function (v) {
        if (!contains(v)) {
            sparse[v] = dense.length;
            dense.push(v);
        }
    }

    arr.forEach(add);

    return {
        contains: contains,
        toArray: function () {
            return dense
        },
        _getDense: function () {
            return dense
        },
        _getSparse: function () {
            return sparse
        }
    }
}

然后,我们可以映射naturalSet引进集:

var set = function (arr, valueOf) {
    var natSet = naturalSet(arr.map(valueOf));
    return {
        contains: function (item) {
            return natSet.contains(valueOf(item))
        },
        toArray: function () {
            var sparse = natSet._getSparse();
            var res = natSet._getDense().map(function (i) {
                return arr[sparse[i]];
            });
            return res;
        }
    }
}

最后,我们可以引入路口:

var intersection = function(arr1, arr2, valueOf) {
   return set(arr2.filter(set(arr1, valueOf).contains), valueOf).toArray();
}

所以,依靠你的工作数据的结构可以帮助你的时候。



Answer 5:

without using underscorejs,
here is the pretty simple method i got solution ... 

a = [{'key':'123'},{'key':'222'},{'key':'333'}]
b = [{'key':'123'},{'key':'222'}]

var diff = a.filter(function(item1) {
  for (var i in b) {
    if (item1.key === b[i].key) { return false; }
  };
  return true;
});
console.log('result',diff)


Answer 6:

var a = [{'id':1, 'value':10}, {'id':2, 'value':20}];
var b = [{'id':1, 'value':10}, {'id':4, 'value':40}];

var c = _.difference(a.map(e => e.id), b.map(e =>e.id));
var array = [];
array = a.map(e => {
   if(c.includes(e.id)){
     return e;
   }
}).filter(r=>r);


Answer 7:

请原谅我在这里跳晚,但是这可能会帮助:

array_of_objects = 
    // return the non-matching items (without the expected properties)
    _.difference(array_of_objects,
        // filter original list for items with expected properties
        _.where(
            // original list
            array_of_objects,
            // expected properties
            {'id':1, 'value':10}
        )
    )


Answer 8:

不知道为什么这些答案是如此复杂,除非我失去了一些东西?

 var a = [{'id':1, 'value':10}, {'id':2, 'value':20}]; var b = [{'id':1, 'value':10}, {'id':4, 'value':40}]; // Or use lodash _.differenceBy const difference = (array1, array2, prop = 'id') => array1.filter(item1 => !array2.some(item2 => item2[prop] === item1[prop], ), ); // In one array. console.log(difference(a, b)); // Intersection. console.log([...difference(a, b), ...difference(b, a)]); 



文章来源: using underscore's “difference” method on arrays of objects