JavaScript数组中条目的两两组合

8
我得到了一个 JavaScript 中的条目数组,例如:
var entries = ["cat", "dog", "chicken", "pig"];

我现在想迭代它们所有唯一的成对组合。在这个例子中,我想看到:
("cat", "dog"),
("cat", "chicken"),
...

在其他语言中,比如scala,这非常容易。只需要做:
entries.combinations(2)

在JavaScript库中是否有类似的方法或函数?还是我必须用嵌套循环自己写一个丑陋的方法?

是的,你必须自己编写它。 - xdazz
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才能正常工作。
另外,重复的值是“undefined”,而不是有4个由3个数组组成。我相信有一种更优雅的处理方法。
参考MDN Array.prototype.map() 编辑:
这将为您提供适当的成对组合。
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;
});

数组的splice()方法 - 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;
});

如果你发现经常需要使用它,这是原型的链接:http://jsfiddle.net/rlemon/qtxHx/。 - rlemon

3

啊,太糟糕了。没错,这就是我的问题!看来我在搜索时没有找到它。 - fozziethebeat
我希望 Lodash 有这个功能。 - m.spyratos

1

使用ES6语法,可以使用@rlemon's answer的缩写版本:

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

这段代码解决了 undefined 的问题,并根据提问者的要求仅输出唯一的组合。

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]
]

我认为reduce和forEach在IE8上不起作用。请参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Browser_compatibility - Stuart
forEach在这里只是用于演示,实际上并不相关。虽然你说reduce在IE8上有问题,但我相信你可以通过shim解决它。 - Andreas Presthammer
我发现我的解决方案并没有真正回答这个问题。他要求所有组合,但我提供的解决方案只给出了数组中所有偶数和奇数元素的组合。 - Andreas Presthammer

0
这是一个通用的TypeScript实现(您可以通过删除类型来获得纯JS):
// 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);

0

最有效且简单的解决方案可能是使用reduce和slice。但是,如果你只想获取值,可以使用生成器。

// 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 ]
*/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接