I come from a Ruby background, which features an enumerable class. In Ruby, I can easily find combinations of array elements.
array.combination(2).count
I know that JavaScript doesn't feature such built in functions, so I was wondering how I could implement this in JS. I was thinking something like
I have an array as follows
var numbers = [9,7,12]
var combos = []
for (var i = 0; i < numbers.length; i++) {
combos.push([numbers[i], numbers[i+1])
}
By the way, the possible combos are
[9,7], [9,12] and [7,12]
so by calling the length function on this array, 3 would be returned.
Any ideas?
How about:
for (var i = 0; i < numbers.length; i++)
for (var j = i + 1; j < numbers.length; j++)
combos.push([numbers[i], numbers[j]]);
Are you strictly talking about 2-combinations of the array or are you interested in a k-combinations solution?
Found this in this gist
function k_combinations(set, k) {
var i, j, combs, head, tailcombs;
if (k > set.length || k <= 0) {
return [];
}
if (k == set.length) {
return [set];
}
if (k == 1) {
combs = [];
for (i = 0; i < set.length; i++) {
combs.push([set[i]]);
}
return combs;
}
// Assert {1 < k < set.length}
combs = [];
for (i = 0; i < set.length - k + 1; i++) {
head = set.slice(i, i+1);
tailcombs = k_combinations(set.slice(i + 1), k - 1);
for (j = 0; j < tailcombs.length; j++) {
combs.push(head.concat(tailcombs[j]));
}
}
return combs;
}
Here's a recursive function, which should work for any number:
function combination(arr, num) {
var r= [];
for(var i = 0 ; i < arr.length ; i++) {
if(num===1) r.push([arr[i]]);
else {
combination(arr.slice(i+1), num-1).forEach(function(val) {
r.push([].concat(arr[i], val));
});
}
}
return r;
} //combination
Working Fiddle
Related
What is the most JS-style way to solve the following problem?
Given an array A, find all arrays B, such that for i <= A.length: B[i] <= A[i]. Example of what I expect:
#Input
A = [1,2,0]
#Output
B = [[0,0,0],
[1,0,0],
[1,1,0],
[1,2,0],
[0,1,0],
[0,2,0]]
In Python I used:
B = [[]];
for t in [range(e+1) for e in A]:
B = [x+[y] for x in B for y in t]
Thanks in advance!
Use the following code (any loop for one item of the array a):
var a = [1, 2, 0], b = [];
for (var i = 0; i < a[0]; i++) {
for (var j = 0; j < a[1]; j++) {
for (var k = 0; k <= a[2]; k++) {
b.push([i, j, k]);
}
}
}
If you know the numebr of items in the array a only on runtime, use the following recursive function:
function fillArray(source, dest, recursionLevel, tempArr) {
if (recursionLevel >= source.length) {
dest.push(tempArr);
return;
}
for (var i = 0; i <= source[recursionLevel]; i++) {
var tempArr2 = tempArr.slice(); // Copy tempArr
tempArr2.push(i);
fillArray(source, dest, recursionLevel + 1, tempArr2);
}
}
fillArray(a, b, 0, []);
I found this solution. I'm sure it can be coded in a much nicer way. However, it works and I hope you find it useful
all_combinations(A){
var B = [];
for (var i = 0; i < A[0] + 1; i++) {
B.push([i]);
}
for (var i = 1; i < A.length; i++) {
var _tmp_array = [];
for (var j = 0; j < A[i] + 1; j++) {
for (var k = 0; k < B.length; k++) {
var _new_element = B[k].concat([j]);
_tmp_array.push(_new_element);
}
}
B = _tmp_array;
}
return B;
}
Given arr = ['mat','cat','fat']
A function getComb(arr, n = 2) where n is the number of words each combination must have.
Expected results:
mat cat
mat fat
cat fat
I could not modify the code below any further to get the desired results. Any idea? thx
Thanks to Knskan3:
'getCombinations': (arr, n) => {
let i, j, k, elem, l = arr.length, childperm, ret = [];
if (n === 1) {
for (let i = 0; i < arr.length; i++) {
ret.push([arr[i]]);
}
return ret;
}
else {
for (i = 0; i < l; i++) {
elem = arr.shift();
for (j = 0; j < elem.length; j++) {
childperm = lib.getCombinations(arr.slice(), n - 1);
for (k = 0; k < childperm.length; k++) {
ret.push([elem[j]].concat(childperm[k]));
}
}
}
return ret;
}
},
I suggest a space-efficient generator function:
// Generate all k-combinations of first n array elements:
function* combinations(array, k, n = array.length) {
if (k < 1) {
yield [];
} else {
for (let i = --k; i < n; i++) {
for (let combination of combinations(array, k, i)) {
combination.push(array[i]);
yield combination;
}
}
}
}
// Example:
console.log(...combinations(['mat', 'cat', 'fat'], 2));
OBJECTIVE
I am trying to highlight the dfferences between two arrays. Please note that arr1 and arr2 will vary in length and have multiple types present (strings and numbers).
MY CODE
function diff(arr1, arr2) {
var diffArr = [];
if (arr1.length >= arr2.length) {
for (var i = 0; i < arr1.length; i++){
if (arr2.indexOf(arr1[i]) < 0) {
diffArr.push(arr1[i]);
}
}
} else {
for (var j = 0; j < arr2.length; j++){
if (arr1.indexOf(arr2[j]) < 0) {
diffArr.push(arr2[j]);
}
}
}
return diffArr;
}
ISSUES
diff([1, 2, 'cat', 'fish'], [1, 2, 3,'dog']); //returns only ['cat', 'fish']
I am pretty sure that my code is only returning the duplicates in one of the arrays via diffArr.push (even if there are unique values in both arrays). However, I am unsure how to overcome this.
My references
Removes Duplicates from Javascript Arrays
Removed Duplicates from an Array Quickly
Javascript Array Difference
Your code currently only crawls through one array (let's call it A) and pushes in all the A values that don't exist in B. You never go the other way and push in the B values that don't exist in A. There's also no need to have different behavior based on which array is longer. Here is the final answer in a simple way:
function diff(arr1, arr2) {
var diffArr = [];
for (var i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) < 0) diffArr.push(arr1[i]);
}
for (var j = 0; j < arr2.length; j++) {
if (arr1.indexOf(arr2[j]) < 0) diffArr.push(arr2[j]);
}
return diffArr;
}
And in a slightly more functional way:
function diff(arr1, arr2) {
var elsIn1Not2 = arr1.filter(function(el){ return arr2.indexOf(el) < 0; });
var elsIn2Not1 = arr2.filter(function(el){ return arr1.indexOf(el) < 0; });
return elsIn1Not2.concat(elsIn2Not1);
}
Both functions return [ 'cat', 'fish', 3, 'dog' ] for your example.
function diff(arr1, arr2) {
var diffArr = {};
if (arr1.length >= arr2.length) {
for (var i = 0; i < arr1.length; i++){
if (arr2.indexOf(arr1[i]) < 0) {
diffArr[arr1[i]] = 1;
}
}
} else {
for (var j = 0; j < arr2.length; j++){
if (arr1.indexOf(arr2[j]) < 0) {
diffArr[arr2[j]] = 2;
}
}
}
return diffArr.keys();
}
i am trying to make a for loop out of a var variable but it doesn't work. For some reason tempArray.length is always undefined, it never return anything different. Can anyone help ?
for (i = 0; i < arr.length; i++) {
tempArray = arr[i];
for (k = 0; k <= tempArray.length; i++) {
if (tempArray[k] != /[0-9]+/) {
countinue;
}
var tempArray = [];
for (i = 0; i < arr.length; i++) {
tempArray = arr[i];
}
for (k = 0; k <= tempArray.length; i++) {
if (tempArray[k] != /[0-9]+/) {
countinue;
}
}
Temp array needs to be set to an array.
Loop through and build tempArray first, then loop through the temp array and do what ever you need to.
The following code will generate 10 arrays, each with 10 subarrays, each with 10 subarrays, each with 10 subarrays.
paths = [];
for (var i = 0, len_i = 10; i < len_i; ++i) { // 1st dimension
paths.push([]);
for (var j = 0, len_j = 10; j < len_j; ++j) { // 2nd dimension
paths[i].push([]);
for (var k = 0, len_k = 10; k < len_k; ++k) { // 3rd dimension
paths[i][j].push([]);
for (var l = 0, len_l = 10; l < len_l; ++l) { // 4th dimension
paths[i][j][k].push([]);
paths[i][j][k][l] = [];
}
}
}
}
I will eventually need to do this with more dimensions and am curious to know if any ingenious developers out there can accomplish this with a function of the form:
function makePaths(quantityInEachArray, dimensions) {
paths = [];
quantityInEachArray = (typeof quantityInEachArray === "undefined") ? 10 : quantityInEachArray;
dimensions = (typeof dimensions === "undefined") ? 4 : dimensions;
// Do some magic
return paths;
}
That function, in its default form, would return the same thing as the for loops I demonstrated above.
I understand that this is not a standard practice but I am doing it for a very specific reason and need to test the performance of it.
How do I modify this code to produce nth dimensional arrays?
You can use recursive function:
function nthArray(n, l) {
if(n < 1) return;
var arr = new Array(l);
for(var i=0; i<l; ++i)
arr[i] = nthArray(n-1, l);
return arr;
}
A simple magic would be (without recursion):
paths = []
arrays = [paths]
for (var i = 0; i < dimensions; i++) {
tmpArr = []
for (var k = 0; k < arrays.length; k++) {
for (var j = 0; j < size; j++) {
val = []
tmpArr.push(val)
arrays[k].push(val)
}
}
arrays = tmpArr
}
(I am not very fluent in javascript, you probably need to declare vars at the beginning and every thing, but that's the idea)