什么是计算使用Javascript阵列设定的差最快或最优雅的方式?什么是计算使用Javascript

2019-05-08 16:14发布

AB两套。 我在寻找快或优雅的方式来计算差集( A - BA \B两者之间,根据自己的喜好)。 两组的存储和操作类似于JavaScript数组,正如标题所说。

笔记:

  • 具体Gecko的招数都还好
  • 我宁愿坚持本地函数(但我愿意接受一个轻量级库,如果它的方式更快)
  • 我见过,但是没有测试过, JS.Set (参见前一点)

编辑:我注意到了有关含重复元素集的评论。 当我说“设置”我指的是数学定义,这意味着(除其他事项外),它们不包含重复的元素。

Answer 1:

如果不知道这是否是最有效的,但也许是最短

A = [1, 2, 3, 4];
B = [1, 3, 4, 7];

diff = A.filter(function(x) { return B.indexOf(x) < 0 })

console.log(diff);

已更新至ES6:

A = [1, 2, 3, 4];
B = [1, 3, 4, 7];

diff = A.filter(x => !B.includes(x) );

console.log(diff);


Answer 2:

那么,7年后,随着ES6的设置对象它很容易(但还不是一样紧凑蟒蛇A - B),据说速度比indexOf对于大数组:

let a = new Set([1,2,3,4]);
let b = new Set([5,4,3,2]);

console.log(new Set([...a].filter(x => !b.has(x)))); //a\b => {1}
console.log(new Set([...b].filter(x => !a.has(x)))); //b\a => {5}
console.log(new Set([...a].filter(x => b.has(x))));  //a∩b => {2,3,4}


Answer 3:

您可以使用一个对象作为地图,以避免线性扫描B的每个元素A作为user187291的回答 :

function setMinus(A, B) {
    var map = {}, C = [];

    for(var i = B.length; i--; )
        map[B[i].toSource()] = null; // any other value would do

    for(var i = A.length; i--; ) {
        if(!map.hasOwnProperty(A[i].toSource()))
            C.push(A[i]);
    }

    return C;
}

非标准toSource()方法来获得独特的属性名称; 如果所有的元素已经有唯一的字符串表示(如与数字的情况下),则可以通过降低加速码toSource()调用。



Answer 4:

最短的,使用jQuery是:

 var A = [1, 2, 3, 4]; var B = [1, 3, 4, 7]; var diff = $(A).not(B); console.log(diff.toArray()); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 



Answer 5:

我将散列数组B,然后保持的值从所述数组A中乙不存在:

function getHash(array){
  // Hash an array into a set of properties
  //
  // params:
  //   array - (array) (!nil) the array to hash
  //
  // return: (object)
  //   hash object with one property set to true for each value in the array

  var hash = {};
  for (var i=0; i<array.length; i++){
    hash[ array[i] ] = true;
  }
  return hash;
}

function getDifference(a, b){
  // compute the difference a\b
  //
  // params:
  //   a - (array) (!nil) first array as a set of values (no duplicates)
  //   b - (array) (!nil) second array as a set of values (no duplicates)
  //
  // return: (array)
  //   the set of values (no duplicates) in array a and not in b, 
  //   listed in the same order as in array a.

  var hash = getHash(b);
  var diff = [];
  for (var i=0; i<a.length; i++){
    var value = a[i];
    if ( !hash[value]){
      diff.push(value);
    }
  }
  return diff;
}


Answer 6:

掺入来自克里斯托弗的想法,并假设两对数组和对象/散列(非标准迭代方法each和朋友),我们可以得到设置差,并和交线性时间在大约20行总数:

var setOPs = {
  minusAB : function (a, b) {
    var h = {};
    b.each(function (v) { h[v] = true; });
    return a.filter(function (v) { return !h.hasOwnProperty(v); });
  },
  unionAB : function (a, b) {
    var h = {}, f = function (v) { h[v] = true; };
    a.each(f);
    b.each(f);
    return myUtils.keys(h);
  },
  intersectAB : function (a, b) {
    var h = {};
    a.each(function (v) { h[v] = 1; });
    b.each(function (v) { h[v] = (h[v] || 0) + 1; });
    var fnSel = function (v, count) { return count > 1; };
    var fnVal = function (v, c) { return v; };
    return myUtils.select(h, fnSel, fnVal);
  }
};

这假定eachfilter是为数组定义,和我们有两个实用方法:

  • myUtils.keys(hash) :返回与散列的键阵列

  • myUtils.select(hash, fnSelector, fnEvaluator)返回与调用的结果的阵列fnEvaluator上的量,键/值对fnSelector返回true。

select()被宽松地通过Common Lisp的启发,并且仅仅filter()map()集于一身。 (这将是更好地让他们上定义Object.prototype ,但这样做沉船浩劫与jQuery,所以我决定静态实用方法。)

性能:与测试

var a = [], b = [];
for (var i = 100000; i--; ) {
  if (i % 2 !== 0) a.push(i);
  if (i % 3 !== 0) b.push(i);
}

给出两套50,000 66,666和元素。 具有这些值的AB约需75ms,而并和交约为150ms的每个。 (苹果Safari浏览器4.0,使用javascript日期时间。)

我认为这是20行代码像样的回报。



Answer 7:

使用Underscore.js (库功能JS)

>>> var foo = [1,2,3]
>>> var bar = [1,2,4]
>>> _.difference(foo, bar);
[4]


Answer 8:

至于禁食方式,这是不那么优雅,但我已经运行一些测试,以确保万无一失。 载入一个阵列作为一个对象远快以处理大量:

var t, a, b, c, A;

    // Fill some arrays to compare
a = Array(30000).fill(0).map(function(v,i) {
    return i.toFixed();
});
b = Array(20000).fill(0).map(function(v,i) {
    return (i*2).toFixed();
});

    // Simple indexOf inside filter
t = Date.now();
c = b.filter(function(v) { return a.indexOf(v) < 0; });
console.log('completed indexOf in %j ms with result %j length', Date.now() - t, c.length);

    // Load `a` as Object `A` first to avoid indexOf in filter
t = Date.now();
A = {};
a.forEach(function(v) { A[v] = true; });
c = b.filter(function(v) { return !a[v]; });
console.log('completed Object in %j ms with result %j length', Date.now() - t, c.length);

结果:

completed indexOf in 1219 ms with result 5000 length
completed Object in 8 ms with result 5000 length

然而, 这只字符串 。 如果您打算比较数值的设置,你会想用映射结果parseInt函数



Answer 9:

一些简单的功能,从@米兰的答案借贷:

const setDifference = (a, b) => new Set([...a].filter(x => !b.has(x)));
const setIntersection = (a, b) => new Set([...a].filter(x => b.has(x)));
const setUnion = (a, b) => new Set([...a, ...b]);

用法:

const a = new Set([1, 2]);
const b = new Set([2, 3]);

setDifference(a, b); // Set { 1 }
setIntersection(a, b); // Set { 2 }
setUnion(a, b); // Set { 1, 2, 3 }


Answer 10:

这工作,但我认为另外一个是更短,太优雅

A = [1, 'a', 'b', 12];
B = ['a', 3, 4, 'b'];

diff_set = {
    ar : {},
    diff : Array(),
    remove_set : function(a) { ar = a; return this; },
    remove: function (el) {
        if(ar.indexOf(el)<0) this.diff.push(el);
    }
}

A.forEach(diff_set.remove_set(B).remove,diff_set);
C = diff_set.diff;


文章来源: What is the fastest or most elegant way to compute a set difference using Javascript arrays?