6

我在 javascript 中获得了一组条目,例如:

var entries = ["cat", "dog", "chicken", "pig"];

我现在想遍历它们的所有独特的成对组合。在这个例子中,我想看看:

("cat", "dog"),
("cat", "chicken"),
...

在其他语言中,比如 scala,这非常简单。你只是做

entries.combinations(2)

javascript库中是否有类似的方法或函数?还是我只需要自己用嵌套循环的丑陋方式编写它?

4

6 回答 6

6
var arr = ["cat","dog","chicken","pig"].map(function(item,i,arr) {
    return arr.map(function(_item) { if( item != _item) return [item, _item];});
});

这将返回预期的结果。有一些警告,它在没有 shims 的旧浏览器中不起作用。

此外,重复值是“未定义”,而不是 4 个 3 个数组。我相信有一种更优雅的方式来处理这个问题。

Array.prototype.map() - MDN

编辑

这将为您提供正确的成对组合。

var arr = ["cat","dog","chicken","pig"].map(function(item,i,arr) {
    var tmp = arr.map(function(_item) { if( item != _item) return [item, _item];});
    return tmp.splice(tmp.indexOf(undefined),1), tmp;
});

数组拼接方法 - MDN

这是相同代码的更具可读性的版本。

var myArray = ["cat", "dog", "chicken", "pig"];
var pairwise = myArray.map(function(item, index, originalArray) {
    var tmp = originalArray.map(function(_item) {
        if (item != _item) {
            return [item, _item];
        }
    });
    tmp.splice(tmp.indexOf(undefined), 1); // because there is now one undefined index we must remove it.
    return tmp;
});
于 2012-12-22T22:37:43.373 回答
3

据我所知不是。我认为你必须坚持嵌套循环。

此处提出了一个类似的问题:Output each combination of a array of a numbers with javascript也许您可以在那里找到答案。

于 2012-08-24T06:34:55.523 回答
0

查看问题后,此答案无法正确解决问题。该问题要求所有组合,但下面的函数组合了数组的所有相邻偶数和奇数索引。

这是我使用reduce做的成对实现

function pairwise(arr) {
    return arr.reduce(function(acc, current, index) {
        var isFirstPair = (index % 2) === 0;

        if (isFirstPair) {
            acc.push([current]);
        } else {
            lastElement = acc[acc.length - 1];
            lastElement.push(current);
        }

        return acc;
    }, []);
};

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

var res = pairwise(nums);

res.forEach(function(elem) {
   console.log(elem); 
});

回报:

[
  [1, 2]
  [3, 4]
  [5, 6]
]
于 2012-12-22T22:07:23.917 回答
0

使用 ES6 语法,可以使用较短版本的@rlemon 答案

["cat","dog","chicken","pig"].sort().reduce(
  (acc, item, i, arr) => acc.concat(
    arr.slice(i + 1).map(_item => [item, _item])
  ),
[])

This takes care of undefineds, and also outputs only unique combinations, as per OP's question.

于 2019-01-19T05:17:21.310 回答
0

Here's a generic TypeScript implementation (you can get the pure JS by removing the types):

// Returns an array of size
const sizedArray = (n: number): null[] => Array(n).fill(null);

// calls the callback n times
const times = (n: number, cb: () => void): void => {
  while (0 < n--) {
    cb();
  }
};

// Fills up the array with the return values of subsequent calls of cb
const fillWithCb = <T>(n: number, cb: () => T): T[] => sizedArray(n).map(cb);

// Generic to produce pairwise, 3 element wise etc..
const nWise = (n: number): (<T>(array: T[]) => T[][]) => <T>(
  array: T[]
): T[][] => {
  const iterators = fillWithCb(n, () => array[Symbol.iterator]());
  iterators.forEach((it, index) => times(index, () => it.next()));
  return fillWithCb(array.length - n + 1, () =>
    iterators.map(it => it.next().value)
  );
};

// curried nWise with 2 -> pairWise
export const pairWise = nWise(2);
于 2019-09-26T15:10:20.173 回答
0

The most effective and simple solution can be reduced and slice. However, if you just want to get values. You can use a generator.

// Util class 
function pairWise(arr) {
     return {
         [Symbol.iterator]: function *() {
             for(let i =0; i< arr.length; i= i+2)
             yield arr.slice(i, i+2)
         }
     }
    } 
 // How to use it
for(ent of pairWise([1,2,3,4,5,6, 7])){
    console.log(ent)
}
// Output
/*
[ 1, 2 ]
[ 3, 4 ]
[ 5, 6 ]
[ 7 ]
*/
于 2019-09-26T15:24:32.760 回答