最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Pairwise combinations of entries in a javascript array - Stack Overflow

programmeradmin3浏览0评论

I'm given an array of entries in javascript, such as :

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

I'd now like to iterate over all unique pairwise binations of them. In this example, I'd like to see:

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

In other languages, like scala, this is super easy. You just do

entriesbinations(2)

is there a similar method or function in a library for javascript? Or do I just have to write it myself the ugly way with nested loops?

I'm given an array of entries in javascript, such as :

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

I'd now like to iterate over all unique pairwise binations of them. In this example, I'd like to see:

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

In other languages, like scala, this is super easy. You just do

entries.binations(2)

is there a similar method or function in a library for javascript? Or do I just have to write it myself the ugly way with nested loops?

Share Improve this question edited Aug 24, 2012 at 6:35 xdazz 161k38 gold badges253 silver badges278 bronze badges asked Aug 24, 2012 at 6:30 fozziethebeatfozziethebeat 1,1802 gold badges12 silver badges28 bronze badges 1
  • Yes, you have to write it yourself. – xdazz Commented Aug 24, 2012 at 6:39
Add a ment  | 

6 Answers 6

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

This will return the expected results. There are caveats, it does not work in older browsers without shims.

Also the duplicate value is 'undefined' instead of there being 4 arrays of 3. I'm sure there is a more graceful way to handle this.

Array.prototype.map() - MDN

edit

this will give you the proper pairwise binations.

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;
});

Array splice method - MDN

and here is a more readable version of the same code.

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;
});

Not as far as I know. I think you have to stick to nested loops.

A similar question has been asked here: Output each bination of an array of numbers with javascript maybe you can find an answer there.

With ES6 syntax, one can use a shorter version of @rlemon's answer:

["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 binations, as per OP's question.

After reviewing the question, this answer doesn't correctly solve the question. The question asks for all binations, but the function below bines all adjacent even and odd indexes of the array.

Here is a pairwise implementation I did using 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); 
});

Returns:

[
  [1, 2]
  [3, 4]
  [5, 6]
]

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);

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 ]
*/
发布评论

评论列表(0)

  1. 暂无评论