简体   繁体   English

笛卡尔积没有重复

[英]Cartesian product without duplicates

I am using a cartesian product function that given [1], [1,2,3], [1,2,3] returns 9 combinations: 我正在使用笛卡尔积函数给出[1], [1,2,3], [1,2,3]返回9种组合:

[ [ 1, 1, 1 ],
  [ 1, 2, 1 ],
  [ 1, 3, 1 ],
  [ 1, 1, 2 ],
  [ 1, 2, 2 ],
  [ 1, 3, 2 ],
  [ 1, 1, 3 ],
  [ 1, 2, 3 ],
  [ 1, 3, 3 ] ]

But I need to remove those with the same items regardless of the order, so [ 1, 3, 1 ] and [ 1, 1, 3 ] are the same to me. 但是无论顺序如何,我都需要删除那些具有相同项目的项目,因此[ 1, 3, 1 ][ 1, 1, 3 ]对我来说是一样的。 The result should contain 6 items: 结果应包含6个项目:

[ [ 1, 1, 1 ],
  [ 1, 2, 1 ],
  [ 1, 3, 1 ],
  [ 1, 2, 2 ],
  [ 1, 3, 2 ],
  [ 1, 3, 3 ] ]

I can write a function that compares all possible pairs with _.xor , but for larger numbers it will probably be very inefficient. 我可以编写一个函数来比较所有可能的对与_.xor ,但对于较大的数字,它可能效率非常低。 Is there a good way in Javascript to do this? 有没有一个很好的方法在Javascript中执行此操作? An efficient way to compare all possible pairs or an algorithm for cartesian product without duplicates? 比较所有可能的对或笛卡尔积的算法而不重复的有效方法?

sort each array of the cartesian product 对笛卡尔积的每个数组进行排序

[ 1, 2, 1 ] -> [1 , 1 , 2]
[ 1, 1, 2 ] -> [1 , 1 , 2]

then gather these sorted arrays into a set, that will remove the duplicates. 然后将这些排序的数组收集到一个集合中,这将删除重复项。

Of course, you can do that while constructing the cartesian product rather than afterward. 当然,你可以在构建笛卡尔积而不是之后的同时做到这一点。

JavaScript has Set and Map , however they compare objects and arrays by reference rather than by value, so you cannot take advantage of it directly. JavaScript具有SetMap ,但它们通过引用而不是值来比较对象和数组,因此您无法直接利用它。 The idea is to use a key function which sorts and json encodes the items before putting it in a set. 我们的想法是使用一个键函数,在将它放入集合之前对其进行排序和json编码。

pure ES5: 纯ES5:

 function product(sets) { if (sets.length > 0) { var head = sets[0]; var tail = product(sets.slice(1)); var result = []; head.forEach(function(x) { tail.forEach(function(xs) { var item = xs.slice(0); item.unshift(x); result.push(item); }); }); return result; } else { return [[]]; } } function myKeyFn(item) { return JSON.stringify(item.slice(0).sort()); } function uniqBy(items, keyFn) { var hasOwn = Object.prototype.hasOwnProperty, keyset = {}; return items.filter(function(item) { var key = keyFn(item); if (hasOwn.call(keyset, key)) { return false; } else { keyset[key] = 1; return true; } }); } function uniqProduct(sets) { return uniqBy(product(sets), myKeyFn); } function log(x) { console.log(x); var pre = document.createElement('pre'); pre.appendChild(document.createTextNode(x)); document.body.appendChild(pre); } log(uniqProduct([[1],[1,2,3],[1,2,3]]).map(JSON.stringify).join("\\n")); 
 <pre></pre> 

lodash + modern JavaScript : lodash + 现代JavaScript

// Note: This doesn't compile on current babel.io/repl due to a bug

function product(sets) {
  if (sets.length > 0) {
    const [x, ...xs] = sets;
    const products = product(xs);
    return _.flatMap(x, head => products.map(tail => [head, ...tail]));
  } else {
    return [[]];
  }
}

function uniqProduct(sets) {
  return _.uniqBy(product(sets), x => JSON.stringify(x.slice(0).sort()));
}

console.log(uniqProduct([[1],[1,2,3],[1,2,3]]).map(JSON.stringify).join("\n"));

JavaScript has set data structure. JavaScript已设置数据结构。

So store your results in a set where each element of the set is a collection of pairs of numbers from the original sets along with the number of times that number occurs. 因此,将结果存储在一个集合中,集合中的每个元素都是原始集合中数字对的集合,以及该数字出现的次数。

So your result would look something like this: 所以你的结果看起来像这样:

[ 
  {1:3},
  {1:2, 2: 1},
  { 1:2, 3:1},
  { 1:1, 2:2},
  { 1:1, 2:1, 3:1},
  { 1:1, 3:2 }  ]

This way, you won't be able to add the object a second time to the set. 这样,您将无法再次将对象添加到集合中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM