Binomial sub arrays - javascript

I have an A array with n length.
I want to take all possible k (0
for example, if i have A's length is five:
[1,2,3,4,5]
and if k = 3, algorithm must give me B array.
[1,2,3 ]
[1,2, 4 ]
[1,2, 5]
[1, 3,4 ]
[1, 3, 5]
[1, 4,5]
[ 2,3,4 ]
[ 2,3, 5]
[ 2, 4,5]
[ 3,4,5]
Length of B would be equal to n!/k!(n-k)! ('!' means factorial, Newtons method)
I'm using javascript, so in my tags i included it, but it's just algorithm, not necessary written in javascript.

You could do this via a filter method.
In your example you want to receive all permutations of an array, taking a specific number of elements of that array.
You can easily do that in an iterative manner.
Start by taking all permutations of n - 1 elements of an array:
// return all (n - 1) element permutations of an array
var permutations = function(arr) {
return arr.reduce(function(re, value, i) {
// add an array for each element in the original array
return re.concat([arr.filter(function(v, index) {
// drop each element with the same index
return index !== i
})])
}, [])
}
Now permutations([1,2,3]) would return [[1,2], [1,3], [2,3]]
That's always a disjoint set suppose you're having only unique values in the source array.
To receive all 3-element arrays of a 5-element array, you would first calculate the list of 4-element arrays and transform each of them to a 3-element array.
permutations([1,2,3,4]).map(permutations)
=> [[1,2,3] => [[[1,2], [1,3], [2,3]]
,[1,2,4] ,[[1,2], [1,4], [2,4]]
,[1,3,4] ,[[1,3], [1,4], [3,4]]
,[2,3,4] ,[[2,3], [2,4], [3,4]]
] ]
Obviously the problem here is that there are doubles.
That can be solved by dropping all non-unique values.
var unique = function(arr) {
var s = arr.map(function(v) { return "" + v })
return arr.filter(function(v, i) { return s.indexOf("" + v) == i })
}
Packing it all into one function could be done like this:
var permutationsWithLength = function(arr, length) {
var re = [arr]
for (var i = arr.length; i >= length; i--) {
re = re.reduce(function(tmp, perms) {
return unique(temp.concat(permutations(perms)))
}, [])
}
return re
}
I admit that this may not be the fastest approach, especially regarding the unique function, but it's a very generic one and will work for the problem you described even with larger arrays.
Hope it helps ;)

Below is the copy-paste from one of my projects. Don't know if it still works ;)
var choose = function choose_func(elems, len) {
var result = [];
for (var i=0; i<elems.length; i++) {
if (len == 1) {
result.push([elems[i]]);
} else {
var remainingItems = choose_func(elems.slice(i+1, elems.length), len - 1);
for (var j=0; j<remainingItems.length; j++)
result.push([elems[i]].concat(remainingItems[j]));
}
}
return result;
};
var result = choose([1,2,3,4,5], 3)
/*result = [[1,2,3],[1,2,4],[1,2,5],[1,3,4],[1,3,5],
[1,4,5],[2,3,4],[2,3,5],[2,4,5],[3,4,5]] */

Related

Get all possible set of combinations of two arrays as an array of arrays with JavaScript

Please note: the linked question, "How can I create every combination possible for the contents of two arrays?" does not solve this particular question. The persons that labeled that did not fully understand this specific permutation and request.
If you have two arrays (arr1, arr2) with n elements in each array (i.e., each array will be the same length), then the question is: What's the best method to get/determine all the possible matches where elements do not match with other elements in the same array and where order does not matter?
For example, let's say I have:
arr1 = ["A","B","C"];
arr2 = ["Z","Y","X"];
I would like to get back an array of arrays where each element of one array is paired with an element of another array. So the result would be a unique set of arrays:
matches = [
[["A","Z"],["B","Y"],["C","X"]],
[["A","Z"],["B","X"],["C","Y"]],
[["A","Y"],["B","X"],["C","Z"]],
[["A","Y"],["B","Z"],["C","X"]],
[["A","X"],["B","Z"],["C","Y"]],
[["A","X"],["B","Y"],["C","Z"]],
]
Please note, these two arrays would be the same:
[["A","Z"],["B","Y"],["C","X"]]
[["B","Y"],["C","X"],["A","Z"]]
I am trying to do this with vanilla JavaScript but am completely open to using Lodash as well. For an added bonus, since this can get out of control, speed and performance are important. But right now, I am just trying to get something that would yield a proper result set. To limit this, this function would probably not be used with more than two arrays of 50 elements each.
Here is my latest attempt (using lodash):
function getMatches(arr1, arr2){
var matches = [];
for (var arr1i = 0, arr1l = arr1.length; arr1i < arr1l; arr1i++) {
for (var arr2i = 0, arr2l = arr2.length; arr2i < arr2l; arr2i++) {
matches.push(_(arr1).zip(arr2).value());
arr2.push(arr2.shift());
}
}
return matches;
}
[[A, 1], [B, 2]]
is the same as
[[B, 2], [A, 1]]
in your case, which means that the solution depends on what you pair to the first elements of your array. You can pair n different elements as second elements to the first one, then n - 1 different elements as second elements to the second one and so on, so you have n! possibilities, which is the number of possible permutations.
So, if you change the order of the array elements but they are the same pair, they are equivalent, so you could view the first elements as a fixed ordered set of items and the second elements as the items to permutate.
Having arr1 = [a1, ..., an] and arr2 = [b1, ..., bn] we can avoid changing the order of a1. So, you permutate the inner elements and treat the outer elements' order as invariant, like:
const permutations = function*(elements) {
if (elements.length === 1) {
yield elements;
} else {
let [first, ...rest] = elements;
for (let perm of permutations(rest)) {
for (let i = 0; i < elements.length; i++) {
let start = perm.slice(0, i);
let rest = perm.slice(i);
yield [...start, first, ...rest];
}
}
}
}
var other = ['A', 'B', 'C'];
var myPermutations = permutations(['X', 'Y', 'Z']);
var done = false;
while (!done) {
var next = myPermutations.next();
if (!(done = next.done)) {
var output = [];
for (var i = 0; i < next.value.length; i++) output.push([other[i], next.value[i]]);
console.log(output);
}
}
You're just looking for permutations. The first elements of your tuples are always the same, the second ones are permuted so that you get all distinct sets of combinations.
const arr1 = ["A","B","C"];
const arr2 = ["Z","Y","X"];
const result = permutate(arr2).map(permutation =>
permutation.map((el, i) => [arr1[i], el])
);
This implementation uses Typescript and Lodash.
const permutations = <T>(arr: T[]): T[][] => {
if (arr.length <= 2)
return arr.length === 2 ? [arr, [arr[1], arr[0]]] : [arr];
return reduce(
arr,
(acc, val, i) =>
concat(
acc,
map(
permutations([...slice(arr, 0, i), ...slice(arr, i + 1, arr.length)]),
vals => [val, ...vals]
)
),
[] as T[][]
);
};

How to split an array into multple arrays each with a unique name

I have an array = [A,1,0,1,0,1,B,1,0,0,1,A,1]
I need to split this array into multiple arrays. The split will occur at the "A" or "B" position as seen in the new arrays below. The names of the new arrays use the string "group" plus an incremented number starting with 1 or 0.
The end result should look like:
group1 = [A,1,0,1,0,1]
group2 = [B,1,0,0,1]
group3 = [A,1]
I can get the section of the array I need by creating an array (arrTemp), so I can store the positions (indexes) and later use slice() to get the sections I want (A,1,0,1,0,1), (A,1,0,0,1), and (A,1). But I don't know how to store the results of my slice()'s in arrays with unique names incremented by 1.
This is what I have tried so far:
var arr = [A,1,0,1,0,1,B,1,0,0,1,A,1];
arr.forEach(myFunction)
function myFunction(item, index) {
if ((item=="A") || (item=="B")) {
arrTemp.push(index);
arrTemp=arrTemp; //not sure I need this. I did this so it array would be global
}
}
for (var i = 0; i < arr.length; i++){
sectArray = arr.slice(arrTemp[i]+1,arrTemp[i + 1])
'group' + [i] = [arrTemp[i],sectArray]; //here is my problem.
}
It seems like you're trying to dynamically create variables. That seems tricky and probably won't work. What you should probably have is some collection of results. Probably a parent array that holds all of them.
For example:
var containerArray = [];
Then:
for (var i = 0; i < arr.length; i++){
sectArray = arr.slice(arrTemp[i]+1,arrTemp[i + 1])
containerArray[i] = [arrTemp[i],sectArray];
}
Now containerArray will have all of your stuff. You can also do this with an object:
var containerObject = {};
And the same thing after.
you only need one loop here, keep an empty temp array, iterate over arr and keep pushing elements in temp each time you see 'A' or 'B' push temp to final array, and at last push temp once more into final array because last section will be left.
var arr = ['A',1,0,1,0,1,'B',1,0,0,1,'A',1];
var temp = [];
var sectArray = [];
arr.forEach(myFunction)
function myFunction(item, index) {
if (((item=="A") || (item=="B")) && temp.length) {
sectArray.push(temp);
temp = [item];
}else{
temp.push(item);
}
}
sectArray.push(temp);
console.log(sectArray);
Check this solution that use a combination of string and array methods:
var data = ['A',1,0,1,0,1,'B',1,0,0,1,'A',1];
var results = data.toString().split(/(?=[a-zA-Z]+)/)
.map(function(value){
return value.split(',').filter(function (item) {
return item.length ? true: false;
})
})
.map(function(item) {
return item.map(function (value) {
return isNaN(parseInt(value)) ? value : parseInt(value);
})
});
console.log(results);
// results = [["A", 1, 0, 1, 0, 1], ["B", 1, 0, 0, 1], ["A", 1]]
Another solution using Array#reduce function.
var x = ["A", 1, 0, 1, 0, 1, "B", 1, 0, 0, 1, "A", 1];
function reformat(arr) {
var smallArrCounter = 0;
return arr.reduce(function (acc, item) {
if (item === "A" || item === "B") {
acc["group" + (++smallArrCounter)] = [item];
} else {
acc["group" + smallArrCounter].push(item);
}
return acc;
}, {});
}
var result = reformat(x);
console.log(result.group1); // ["A", 1, 0, 1, 0, 1]
console.log(result.group2); // ["B", 1, 0, 0, 1]
console.log(result.group3); // ["A", 1]
There may be a more performant approach that doesn't require two iterations of the array, but my thought is:
Determine the indices of the group delimiters (characters)
Slice the array into groups based on those delimiters, using either the next index as the end, or arr.length if slicing the last group
This has the assumption that the array delimiters may not be known in advance.
const charIndices = [];
const groups = [];
const arr = ['A',1,0,1,0,1,'B',1,0,0,1,'A',1];
// get the indices of the characters
arr.forEach((v, i) => ('' + v).match(/[A-Z]+/) ? charIndices.push(i) : undefined);
// use the found indices to split into groups
charIndices.reduce((a, b, i) => {
a.push(arr.slice(b, charIndices[i+1] ? charIndices[i+1]-1 : arr.length));
return a;
}, groups);
console.log(groups);

recursively putting array elements in their own array

I'm trying to create a function that puts each array element in its own array, recursively.
I think my base case is correct, but my recursive call doesn't appear to be working. any insight?
function ownList(arr){
if (arr.length === 1) {
arr[0] = [arr[0]];
return;
} else {
return arr[0].concat(ownList(arr.slice(1)));
}
}
var arr = [1,2,3]
console.log(ownList(arr))// returns []
//should return [[1],[2],[3]]
Here I'm trying to put each pair in it's own list (recursive only). This code below is correct (update)
function ownListPair(arr){
if (arr.length === 0)
return arr;
else if(arr.length === 1)
return [[arr[0], 0]];
else
return [[arr[0], arr[1]]].concat(ownListPair(arr.slice(2)));
}
// var arr = [3,6,8,1,5]
var arr = [2,7,8,3,1,4]
//returns [ [ 2, 7 ], [ 8, 3 ], [ 1, 4 ]]
console.log(ownListPair(arr))
I prefer this solution for several reasons:
function ownList(a) {
return a.length == 0
? []
: [[a[0]]].concat(ownList(a.slice(1)))
}
It's shorter and more concise
It works for empty arrays as well
The actual wrapping happens only once in the last line. Treating length == 1 separately -- as suggested by others -- is not necessary.
It would more appropriate to make a length of 0 be the null case. Then you just have to get the brackets right. The thing on the left side of the concat should be an array consisting of the array containing the first element.
function ownList(arr) {
return arr.length ? [[arr[0]]].concat(ownList(arr.slice(1))) : [];
}
Here's an alternative, take your pick:
function ownList(arr) {
return arr.length ? [[arr.shift()]] . concat(ownList(arr)) : [];
}
Using a bit of ES6 magic for readability:
function ownList([head, ...tail]) {
return head === undefined ? [] : [[head]] . concat(ownList(tail));
}
Here the [head, ...tail] is using parameter destructuring which pulls the argument apart into its first element (head) and an array of remaining ones (tail).
Instead of concat you could also use the array constructor:
function ownList([head, ...tail]) {
return head === undefined ? [] : Array([head], ...ownList(tail));
}
I think your basic assumption is wrong. What you need to do is check if each item in the array is an array, if not just add the item to the new array, if so have the function run itself on the array item.
That is recursion.
This code does that kind of recursion...
function ownList(arr)
{
var newArr = [];
var length = arr.length;
for (var i = 0; i < length; i++) {
if (typeof(arr[i]) === 'object') {
newArr.push(ownList(arr[i]));
continue;
}
newArr.push([arr[i]]);
}
return newArr;
}
var arr = [1, 2, 3];
console.log(ownList(arr));
Would something like this work:
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]],
result = [];
function flatten(input){
input.forEach(function(el){
if(Array.isArray(el)){
flatten(el)
}else{
result.push([el]);
}
});
}
flatten(arr);
console.log(JSON.stringify(result));
//[[1],[2],[3],["a"],["b"],["c"],["str"]]
JSBIN
Edit:
var result = [];
function flatten(input){
if (input.length === 0){
console.log( "result", result ); //[[1],[2],[3],["a"],["b"],["c"],["str"]]
return;
}
//if zeroth el of input !array, push to result
if (!Array.isArray(input[0])){
result.push(input.splice(0, 1));
flatten(input);
}else{
flatten(input[0]); //else, give input[0] back to flatten
}
}
window.onload = function(){
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]];
flatten(arr);
}
JSBIN
After struggling through this today, turns out that this works :)
function ownList(arr){
//base case:
if (arr.length === 1) {
return [arr];
}
//recurse
//have to do two brackets here --> (arr.slice(0,1)) since length > 1
return [arr.slice(0,1)].concat(ownList(arr.slice(1)));
}
var arr = [1,2,3]
console.log(ownList(arr))// returns [[1],[2],[3]]

Finding nested duplicate arrays in JavaScript. (Nested Array uniq in lodash/underscore)

I am trying to determine if an array of JavaScript arrays contains duplicates. Is this possible? I am first trying to see if I can strip the duplicates out and then do an equality check but I cannot get past the first part. Here is what underscore returns:
var arr1 = [[1,2], [2,3], [1,2]];
var arr2 = _.uniq(arr1);
var arraysAreEqual = _.isEqual(arr1, arr2);
console.log(arraysAreEqual, arr1, arr2);
// true
Jsbin: http://jsbin.com/vogumo/1/edit?js,console
Anyone know of a way to determine if the array contains duplicate arrays?
It's a little sloppy, but (possible)
var arr2 = _.uniq(arr1, function(item) {
return JSON.stringify(item);
});
will give you a correct result
Try This:
var numArray = [1, 7, 3, 0, 9, 7, 8, 6, 2, 3];
var duplicates = [];
var sortednumArray = numArray.sort();
for (var i = 0; i < sortednumArray.length; i++) {
//console.log(sortednumArray[i]);
if (sortednumArray[i] == sortednumArray[i + 1]) {
duplicates.push(sortednumArray[i]);
}
}
if (duplicates.length == 0) {
console.log("Soted Array:");
for(var i = 0; i < sortednumArray.length; i++) {
console.log(sortednumArray[i]);
}
} else {
console.log("Duplicates:");
for(var i = 0; i < duplicates.length; i++){
console.log(duplicates[i]);
}
}
Program pushes all duplicates to an array called 'duplicates' then displays it, but if none are present, it displays the sorted version of numArray
From the underscore.js documentation:
uniq _.uniq(array, [isSorted], [iteratee]) Alias: unique
Produces a
duplicate-free version of the array, using === to test object
equality. If you know in advance that the array is sorted, passing
true for isSorted will run a much faster algorithm. If you want to
compute unique items based on a transformation, pass an iteratee
function.
But arrays can't be strictly compared in JavaScript.
Therefore, you can use a transformation function to enable comparison with uniq. For example:
console.log([1,2] === [1,2]) // false, can't strict compare arrays
console.log([1,2].toString()) // "1,2" - string representation
console.log([1,2].toString() === [1,2].toString()) // true, strings can be compared
var valueToString = function(v) {return v.toString()}; // transform array to string
var arr1 = [[1,2], [2,3], [1,2]];
var arr2 = _.uniq(arr1, false, valueToString); // compare based on transformation
var arraysAreEqual = _.isEqual(arr1, arr2);
console.log("arraysAreEqual:", arraysAreEqual, arr1, arr2);
// false
// [[1, 2], [2, 3], [1, 2]]
// [[1, 2], [2, 3]]
Note that transforming to string is "hacky": you would be better off comparing each value of the array, as discussed in this StackOverflow question.
By using the proposed equals implementation in that question, you would need to implement your own version of uniq that uses equals instead of ===.
The implementation of uniq in Underscore is very straight-forward - it creates a new result array and loops through the given array. If the current value is not already in result, insert it.
console.log("Using array comparison:");
arrayEquals = function (array1, array2) {
// if any array is a falsy value, return
if (!array1 || !array2)
return false;
// compare lengths - can save a lot of time
if (array1.length != array2.length)
return false;
for (var i = 0, l=array1.length; i < l; i++) {
// Check if we have nested arrays
if (array1[i] instanceof Array && array2[i] instanceof Array) {
// recurse into the nested arrays
if (!arrayEquals(array1[i],array2[i]))
return false;
}
else if (array1[i] !== array2[i]) {
return false;
}
}
return true;
};
_.uniqArrays = function(array) {
if (array == null) return [];
var result = [];
for (var i = 0, length = array.length; i < length; i++) {
var value = array[i];
var arrayEqualsToValue = arrayEquals.bind(this, value); // arrayEquals with first argument set to value
var existing = _.find(result, arrayEqualsToValue); // did we already find this?
if (!existing) {
result.push(value);
}
}
return result;
};
var arr3 = _.uniqArrays(arr1);
arraysAreEqual = _.isEqual(arr1, arr3);
console.log("arraysAreEqual:", arraysAreEqual, arr1, arr3); // false
I made a jsbin with all the code, if you want to play around.
In the latest lodash (4.6.1) you could do something like this:
if (_.uniqWith(arr, _.isEqual).length < arr.length) {
// then there were duplicates
}

JavaScript - Separate array into an array of pairs

I have an array of team names which is like this:
teams = ['team1', 'team2', 'team3', 'team4']
I want to create a set of matches based on this, so at the moment, for a set of matches using the teams array you would get:
teamMatches : [
[ teams[0], teams[1] ],
[ teams[2], teams[3] ]
]
My question is, can anyone think of a way to produce this teamMatches array based upon a teams array with length n. The teams array will always be a correct number, 4,8,16 etc. I have tried using Math.pow with 2 to try to produce the brackets with no success.
Any ideas?
A procedural solution:
xs = [0,1,2,3,4,5,6,7,8,9]
result = []
n = 2 // n=3 gives a list of triples, etc
for(var i = 0; i < xs.length; i += n)
result.push(xs.slice(i, i + n))
A functional programming solution:
function zip() {
var args = [].slice.call(arguments, 0);
return args[0].map(function(_, n) {
return args.map(function(a) {return a[n] })
})
}
xs = [0,1,2,3,4,5,6,7,8,9]
result = zip(
xs.filter(function(_, n) { return n % 2 == 0 }),
xs.filter(function(_, n) { return n % 2 != 0 })
)
// [[0,1],[2,3],[4,5],[6,7],[8,9]]
Explanation: zip is a function (built-in in some programming languages, but not in Javascript) that takes N arrays and groups together elements at the same position:
zip([1,2,3], [10,20,30]) -> [ [1,10], [2,20], [3,30] ]
We split an array into even and odd parts:
[0,2,4,6...]
[1,3,5,7...]
and zip them together, getting a list of ordered pairs.
How about this
var teams = ['team1', 'team2', 'team3', 'team4'];
var teamMatches = new Array();
for(var i=0;i<teams.length; i+=2)
{
teamMatches.push([teams[i],teams[i+1]]);
}

Categories