Re-order array in javascript - javascript

Say you have an array like this and I want to reorder it.
var myarray = [
[178, 559, 906, 1252] , [381 , 537 , 937 , 1115] , [346 , 529 , 913 , 1069]
];
What I wanted to do was to loop through each of the arrays, take the 1st value of each array on the first loop and push each into a separate array. The second time the loop runs, take the 2nd value of each array, push those into the separate array and so on and so on. So that the separate array looks like this;
var myNewArray = [178, 381, 346, 559, 537, 529, 906, 937, 913, 1252, 1115, 1069];
I've got so far as to loop through each array and get all of the values, but can't work out the logic to target ONLY the 1st values on the first loop, the 2nd of the second loop etc etc
var arraylength = myarray.length;
for (var i = 0; i < arraylength; i++ ) {
console.log(i+1 + " time around");
var noc = myarray[i].length;
for (var k = 0; k < noc; k++) {
var a = myarray[i][k];
console.log(a);
};
};
Here's a JSFiddle

Okay...
Perhaps this is overboard, but I had a long trip home and some time to kill.
Your algorithm troubles revolve around the fact that you're missing a step.
What you actually need to do is loop through the range of the longest array.
Which means that you need to create a range (an actual range, or just know the min/max bounds of it) that goes from 0 to the max of all of the lengths of all of the arrays.
When you've done that, you need to go through that range, and within that range, you need to go through the list of all arrays (looping through each 2nd-dimension array, per iteration).
For each array, you check if it has an element at the current index.
If it does, add it to the new array.
The first step (the one you're missing) is almost like dealing cards; you have 4 people at the table, but it's actually the 52 cards that you're iterating through on the outside, not the 4 people.
This has a bunch of different names, depending on what you're doing.
This might be a zip a merge a rotation (though rotation doesn't really account for the flattening, just the shuffling).
So without further ado, here are 3 solutions, which are all different takes on this.
The first solution is the more-classical "JavaScript as Java" implementation:
function findMax (arrays) {
var i = 0;
var l = arrays.length;
var max = 0;
var array = [];
for (; i < l; i += 1) {
array = arrays[i];
max = array.length > max ? array.length : max;
}
return max;
}
function rotateAndFlatten (arrays) {
var flattenedArray = [];
var maxLength = findMax(arrays);
var inner = 0;
var outer = 0;
var array;
var currentValue;
for (; outer < maxLength; outer += 1) {
for (inner = 0; inner < arrays.length; inner += 1) {
array = arrays[inner];
currentValue = array[outer];
if (currentValue || currentValue === 0) {
flattenedArray.push(currentValue);
}
}
}
return flattenedArray;
}
var inputArray = [ [1, 2, 3], [4, 5, 6, 7], [8, 9, 10] ];
var outputArray = rotateAndFlatten(inputArray);
document.querySelector(".ResultInput--ES3").textContent = JSON.stringify(inputArray);
document.querySelector(".ResultOutput--ES3").value = JSON.stringify(outputArray);
<div ><pre>Input: <code class="ResultInput ResultInput--ES3"></code></pre></div>
<div ><pre>Output: <code ><output class="ResultOutput ResultOutput--ES3"></output></code></pre></div>
The second is the ES5 way I'm more used to thinking, these days, with partially-applied functions, and working with sets of things one operation at a time, rather than instances of things with manual loop management:
function makeRange (min, max) {
var range = [];
var i = min;
while (i < max) {
range.push(i);
i += 1;
}
return range;
}
function concat (a, b) {
return a.concat(b);
}
function identity (x) {
return x;
}
function max (a, b) {
return b > a ? b : a;
}
function pluck (key) {
return function pluckFrom (obj) {
return obj[key];
};
}
function fillIndexArrays (arrays) {
return function (i) {
return arrays.map(pluck(i));
};
}
function rotateAndFlatten (array) {
var getLength = pluck("length");
var maxLength = array.map(getLength).reduce(max, 0);
var indices = makeRange(0, maxLength);
return indices.map(fillIndexArrays(array)).reduce(concat, []).filter(identity);
}
var inputArray = [ [1, 2, 3], [4, 5, 6, 7], [8, 9, 10] ];
var outputArray = rotateAndFlatten(inputArray);
document.querySelector(".ResultInput--ES5").textContent = JSON.stringify(inputArray);
document.querySelector(".ResultOutput--ES5").value = JSON.stringify(outputArray);
<div ><pre>Input: <code class="ResultInput ResultInput--ES5"></code></pre></div>
<div ><pre>Output: <code ><output class="ResultOutput ResultOutput--ES5"></output></code></pre></div>
And here's the ES6 version of that, which can now use generators and splat operators to greatly simplify the construction of a range, and use lambdas to where code might be compacted and be equally legible (to me/my team):
const max = (a, b) => b > a ? b : a;
const identity = x => x;
const concat = (a, b) => a.concat(b);
function * range (min, max) {
let i = min;
while (i <= max) {
yield i;
i += 1;
}
};
const pluck = (key) => { return (obj) => obj[key]; };
function rotateAndFlatten (arrays) {
const getLength = pluck("length");
const maxLength = arrays.map(getLength).reduce(max, 0);
const indices = [...range(0, maxLength)];
return indices
.map(i => arrays.map(pluck(i)))
.reduce(concat, [])
.filter(identity);
}
var inputArray = [ [1, 2, 3], [4, 5, 6, 7], [8, 9, 10] ];
var outputArray = rotateAndFlatten(inputArray);
document.querySelector(".ResultInput--ES6").textContent = JSON.stringify(inputArray);
document.querySelector(".ResultOutput--ES6").value = JSON.stringify(outputArray);
<div ><pre>Input: <code class="ResultInput ResultInput--ES6"></code></pre></div>
<div ><pre>Output: <code ><output class="ResultOutput ResultOutput--ES6"></output></code></pre></div>
As a bonus, here's how I might implement it if I were writing JS as though I were writing C code that makes me very sad when I have to debug a logic error (but cuts right to the quick of the algorithm):
function init (arrs) {
var max;
var i = 0;
var l = arrs.length;
var max = 0;
for (i = 0; i < l; i++)
if (max < arrs[i].length)
max = arrs[i].length;
var j = 0;
var arr = [];
for (i = 0; i < max; i++)
for(j = 0; j < arrs.length; j++)
if (arrs[j][i] !== undefined)
arr.push(arrs[j][i]);
document.querySelector(".ResultOutput--C").value = JSON.stringify(arr);
}
var arrs = [ [1, 2, 3], [4, 5, 6, 7], [8, 9, 10] ];
document.querySelector(".ResultInput--C").textContent = JSON.stringify(arrs);
init(arrs);
<div ><pre>Input: <code class="ResultInput ResultInput--C"></code></pre></div>
<div ><pre>Output: <code ><output class="ResultOutput ResultOutput--C"></output></code></pre></div>
Hope that gives you something to chew upon, and some insight into the low-level algorithms which might be at play, and the higher-level ways of implementing those lower-level algorithms.

Alternatively you can do it like this: .shift() returns the first item of the array, but note that this solution will alter the original array
var myarray = [
[178, 559, 906, 1252],
[381, 537, 937, 1115],
[346, 529, 913, 1069]
];
var resultArray = [];
var maxlen = Math.max.apply(null, myarray.map(function(i) {
return i.length; }));
var l = 0;
while (l < maxlen) {
var s = 0;
var a = [];
for (i = 0; i < myarray.length; i++) {
a.push(myarray[i].shift());
}
resultArray.push(a);
l++;
s++;
}
console.log(resultArray);

Instead of iterating myarray in the outer loop, and each subarray in the inner one, you should do the opposite. Then it's a bit tricky, because the outer loop iterates the subarrays, but they could have different lengths. I added a done variable to know where to stop.
var myNewArray = [];
for(var i=0, done=false; !done; ++i) {
done = true;
for(var j=0; j<myarray.length; ++j) {
if(i < myarray[j].length) {
done = false;
myNewArray.push(myarray[j][i]);
}
}
}

Lodash has a method called zip that does what you are trying to do.
console.log(_.zip(myarray)); // [[178, 381, 346], [559, 537, 529], [906, 937, 913], [1252, 1115, 1069]]

Related

Push duplicate items into a separate array in Javascript with for loop?

For some reason, the manipulated doubleArray below is not shown in the console. Any variables that I declare after the for loop won't show to the console on both cases. Consider that in the first algorithm, there is only one for loop with x being incremented everytime. Whereas, in the second algorithm, it's a nested for loop. Can someone help me fix my error in both algorithms?
First Algorithm:
var isDuplicate = function() {
var helloWorld = [1,2,3,4,3];
var doubleValue = [];
var x = 0;
for (i = 0; i < helloWorld.length; i++) {
x = x + 1;
if (helloWorld[i] === helloWorld[x] && i !== x) {
doubleValue.push(helloWorld[i])
console.log(helloWorld[i]);
} else {
continue;
}
}
console.log(doubleValue);
};
The second Algorithm:
var isDuplicate = function() {
var helloWorld = [1,2,3,4,3];
var doubleValue = [];
for (i = 0; i < helloWorld.length; i++) {
for (x = 1; x < helloWorld.length; i++) {
if (helloWorld[i] === helloWorld[x] && i !== x) {
doubleValue.push(helloWorld[x]);
}
}
}
console.log(doubleValue);
};
In first algorithm, you are only checking if the number at current index is equal to the number at the next index, meaning you are only comparing numbers at consecutive indexes. First algorithm will work only if you have duplicate numbers on consecutive indexes.
In second algorithm, you are incrementing i in both loops, increment x in nested loop, change x = 1 to x = i + 1 and your error will be fixed.
Here's the fixed second code snippet
var isDuplicate = function() {
var helloWorld = [1,2,3,4,3, 1, 2];
var doubleValue = [];
for (let i = 0; i < helloWorld.length; i++) {
for (let x = i + 1; x < helloWorld.length; x++) {
if (helloWorld[i] === helloWorld[x] && i !== x) {
doubleValue.push(helloWorld[x]);
}
}
}
console.log(doubleValue);
};
isDuplicate();
Heres's another way to find the duplicates in an array, using an object. Loop over the array, if current number is present as key in the object, push the current number in the doubleValue array otherwise add the current number as key-value pair in the object.
const isDuplicate = function() {
const helloWorld = [1,2,3,4,3, 1, 2];
const doubleValue = [];
const obj = {};
helloWorld.forEach(n => obj[n] ? doubleValue.push(n): obj[n] = n);
console.log(doubleValue);
};
isDuplicate();
Not entirely sure what you are trying to do. If you are only looking for a method to remove duplicates you can do the following:
const hello_world = [1, 2, 2, 3, 4, 5, 5];
const duplicates_removed = Array.from(new Set(hello_world));
A set is a data object that only allows you to store unique values so, when converting an array to a set it will automatically remove all duplicate values. In the example above we are creating a set from hello_world and converting it back to an array.
If you are looking for a function that can identify all the duplicates in an array you can try the following:
const hello_world = [1, 2, 2, 3, 4, 5, 5];
const duplicates_found = hello_world.filter((item, index) => hello_world.indexOf(item) != index);
The main problem by finding duplicates is to have nested loop to compare each element of the array with any other element exept the element at the same position.
By using the second algorithm, you can iterate from the known position to reduce the iteration count.
var isDuplicate = function(array) {
var doubleValue = [];
outer: for (var i = 0; i < array.length - 1; i++) { // add label,
// declare variable i
// no need to check last element
for (var j = i + 1; j < array.length; j++) { // start from i + 1,
// increment j
if (array[i] === array[j]) { // compare values, not indices
doubleValue.push(array[i]);
continue outer; // prevent looping
}
}
}
return doubleValue;
};
console.log(isDuplicate([1, 2, 3, 4, 3])); // [3]
You could take an object for storing seen values and use a single loop for getting duplicate values.
const
getDuplicates = array => {
const
seen = {}
duplicates = [];
for (let value of array) {
if (seen[value]) duplicates.push(value);
else seen[value] = true;
}
return duplicates;
};
console.log(getDuplicates([1, 2, 3, 4, 3])); // [3]
Your first algorithm doesn't work because it only looks for duplicates next to each other. You can fix it by first sorting the array, then finding the duplicates. You can also remove the x and replace it by ++i in the loop.
var isDuplicate = function() {
var helloWorld = [1,2,3,4,3,6];
var doubleValue = [];
helloWorld = helloWorld.sort((a, b) => { return a - b });
for (i = 0; i < helloWorld.length; i++) {
if (helloWorld[i] === helloWorld[++i]) {
doubleValue.push(helloWorld[i])
console.log(helloWorld[i]);
} else {
continue;
}
}
console.log(doubleValue);
};
isDuplicate();
For the second algorithm loop, you probably meant x++ instead of i++ in the second loop. This would fix the problem.
var isDuplicate = function() {
var helloWorld = [1,2,3,4,3,4];
var doubleValue = [];
for (i = 0; i < helloWorld.length; i++) {
for (x = i + 1; x < helloWorld.length; x++) {
if (helloWorld[i] === helloWorld[x]) {
doubleValue.push(helloWorld[x]);
}
}
}
console.log(doubleValue);
};
isDuplicate()
The first algorithm can't be fixed, it can only detect consecutive duplicates,
in the second algorithm you increment i in both loops.
To avoid the duplicates beeing listed too often, you should start the second loop with i + 1

Is there any any other way to find in array pair of numbers whose sum are k?

I have an array of integers and a number k. Is it necessary to determine whether there are two numbers in the array whose sum is k?
function findPairs(nums, k) {
var s = [];
var length = nums.length;
for (var i = 0; i < length; i++) {
if (s[nums[i]] === k - nums[i]) {
console.log(nums[i], k - nums[i])
return true;
} else {
s[k - nums[i]] = nums[i];
}
}
return false;
}
var nums = [10, 15, 3, 7]
var k = 17
console.log(findPairs(nums, k))
why my code is not working?
My guess is that you had a syntax error or forgot to actually declare a function, since the code in the current version of your question appears to work as expected.
As an aside, I would suggest using an object or a Set instead of an array to store the other pair, because for large values of k, your s array may consume a lot of memory on some JavaScript engines as a result.
function findPairs(nums, k) {
var s = {};
var length = nums.length;
for (var i = 0; i < length; i++) {
if (s[nums[i]] === k - nums[i]) {
console.log(nums[i], k - nums[i]);
return true;
}
s[k - nums[i]] = nums[i];
console.log(s); // see the lookup table after each iteration
}
return false;
}
var nums = [10, 15, 3, 7];
var k = 17;
console.log(findPairs(nums, k));
Functional solution
const findPairs = (nums, k) =>
nums
.flatMap((v, i, arr) => arr.slice(i + 1).map(w => [v, w]))
.filter(pair => pair[0] + pair[1] === k);
console.log(findPairs([1, 2, 3, 4, 5, 6], 5));

javascript reverse an array without using reverse()

I want to reverse an array without using reverse() function like this:
function reverse(array){
var output = [];
for (var i = 0; i<= array.length; i++){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
However, the it shows [7, 6, 5, 4] Can someone tell me, why my reverse function is wrong? Thanks in advance!
array.pop() removes the popped element from the array, reducing its size by one. Once you're at i === 4, your break condition no longer evaluates to true and the loop ends.
One possible solution:
function reverse(array) {
var output = [];
while (array.length) {
output.push(array.pop());
}
return output;
}
console.log(reverse([1, 2, 3, 4, 5, 6, 7]));
You can make use of Array.prototype.reduceright and reverse it
check the following snippet
var arr = ([1, 2, 3, 4, 5, 6, 7]).reduceRight(function(previous, current) {
previous.push(current);
return previous;
}, []);
console.log(arr);
In ES6 this could be written as
reverse = (array) => array.map(array.pop, [... array]);
No need to pop anything... Just iterate through the existing array in reverse order to make your new one.
function reverse(array){
var output = [];
for (var i = array.length - 1; i> -1; i--){
output.push(array[i]);
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
Edit after answer got accepted.
A link in a comment on your opening post made me test my way VS the accepted answer's way. I was pleased to see that my way, at least in my case, turned out to be faster every single time. By a small margin but, faster non the less.
Here's the copy/paste of what I used to test it (tested from Firefox developer scratch pad):
function reverseMyWay(array){
var output = [];
for (var i = array.length - 1; i> -1; i--){
output.push(array[i]);
}
return output;
}
function reverseTheirWay(array) {
var output = [];
while (array.length) {
output.push(array.pop());
}
return output;
}
function JustDoIt(){
console.log("their way starts")
var startOf = new Date().getTime();
for(var p = 0; p < 10000; p++)
{
console.log(reverseTheirWay([7,6,5,4,3,2,1]))
}
var endOf = new Date().getTime();
console.log("ran for " + (endOf - startOf) + " ms");
console.log("their way ends")
}
function JustDoIMyWay(){
console.log("my way starts")
var startOf = new Date().getTime();
for(var p = 0; p < 10000; p++)
{
console.log(reverseMyWay([7,6,5,4,3,2,1]))
}
var endOf = new Date().getTime();
console.log("ran for " + (endOf - startOf) + " ms");
console.log("my way ends")
}
JustDoIt();
JustDoIMyWay();
Solution to reverse an array without using built-in function and extra space.
let arr = [1, 2, 3, 4, 5, 6, 7];
let n = arr.length-1;
for(let i=0; i<=n/2; i++) {
let temp = arr[i];
arr[i] = arr[n-i];
arr[n-i] = temp;
}
console.log(arr);
Do it in a reverse way, Because when you do .pop() every time the array's length got affected.
function reverse(array){
var output = [];
for (var i = array.length; i > 0; i--){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
Or you could cache the length of the array in a variable before popping out from the array,
function reverse(array){
var output = [];
for (var i = 0, len= array.length; i< len; i++){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
You are modifying the existing array with your reverse function, which is affecting array.length.
Don't pop off the array, just access the item in the array and unshift the item on the new array so that the first element of the existing array becomes the last element of the new array:
function reverse(array){
var output = [],
i;
for (i = 0; i < array.length; i++){
output.unshift(array[i]);
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
If you'd like to modify the array in-place similar to how Array.prototype.reverse does (it's generally inadvisable to cause side-effects), you can splice the array, and unshift the item back on at the beginning:
function reverse(array) {
var i,
tmp;
for (i = 1; i < array.length; i++) {
tmp = array.splice(i, 1)[0];
array.unshift(tmp);
}
return array;
}
var a = [1, 2, 3, 4, 5];
console.log('reverse result', reverse(a));
console.log('a', a);
This piece allows to reverse the array in place, without pop, splice, or push.
var arr = [1, 2, 3, 4, 5];
function reverseArrayInPlace(arr2) {
var half = Math.floor(arr2.length / 2);
for (var i = 0; i < half; i++) {
var temp = arr2[arr2.length - 1 - i];
arr2[arr2.length - 1 - i] = arr2[i];
arr2[i] = temp;
}
return arr2;
}
As you pop items off the first array, it's length changes and your loop count is shortened. You need to cache the original length of the original array so that the loop will run the correct amount of times.
function reverse(array){
var output = [];
var len = array.length;
for (var i = 0; i< len; i++){
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
You're modifying the original array and changing it's size. instead of a for loop you could use a while
function reverse(array){
var output = [];
while(array.length){
//this removes the last element making the length smaller
output.push(array.pop());
}
return output;
}
console.log(reverse([1,2,3,4,5,6,7]));
function rvrc(arr) {
for (let i = 0; i < arr.length / 2; i++) {
const buffer = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = buffer;
}
};
const reverse = (array)=>{
var output = [];
for(let i=array.length; i>0; i--){
output.push(array.pop());
}
console.log(output);
}
reverse([1, 2, 3, 4, 5, 6, 7, 8]);
This happens because every time you do array.pop(), whilst it does return the last index in the array, it also removes it from the array. The loop recalculates the length of the array at each iteration. Because the array gets 1 index shorter at each iteration, you get a much shorter array returned from the function.
This piece of code will work without using a second array. It is using the built in method splice.
function reverse(array){
for (let i = 0; i < array.length; i++) {
array.splice(i, 0, array.splice(array.length - 1)[0]);
}
return array;
}
Here, let's define the function
function rev(arr) {
const na = [];
for (let i=0; i<arr.length; i++) {
na.push(arr[arr.length-i])
}
return na;
}
Let's say your array is defined as 'abca' and contains ['a','b','c','d','e','foo','bar']
We would do:
var reva = rev(abca)
This would make 'reva' return ['bar','foo','e','d','c','b','a'].
I hope I helped!
You can use .map as it is perfect for this situation and is only 1 line:
const reverse = a =>{ i=a.length; return a.map(_=>a[i-=1]) }
This will take the array, and for each index, change it to the length of the array - index, or the opposite side of the array.
with reverse for loop
let array = ["ahmet", "mehmet", "aslı"]
length = array.length
newArray = [];
for (let i = length-1; i >-1; i--) {
newArray.push(array[i])
}
console.log(newArray)
And this one:
function reverseArray(arr) {
let top = arr.length - 1;
let bottom = 0;
let swap = 0;
while (top - bottom >= 1) {
swap = arr[bottom];
arr[bottom] = arr[top];
arr[top] = swap;
bottom++;
top--;
}
}
function reverse(arr) {
for (let i = 0; i < arr.length - 1; i++) {
arr.splice(i, 0, arr.pop())
}
return arr;
}
console.log(reverse([1, 2, 3, 4, 5]))
//without another array
reverse=a=>a.map((x,y)=>a[a.length-1-y])
reverse=a=>a.map((x,y)=>a[a.length-1-y])
console.log(reverse(["Works","It","One","Line"]))
One of shortest:
let reverse = arr = arr.map(arr.pop, [...arr])
This is an old question, but someone may find this helpful.
There are two main ways to do it:
First, out of place, you basically push the last element to a new array, and use the new array:
function arrReverse(arr) {
let newArr = [];
for(let i = 0; i<arr.length; i++){
newArr.push(arr.length -1 -i);
}
return newArr;
}
arrReverse([0,1,2,3,4,5,6,7,8,9]);
Then there's in place. This is a bit tricky, but the way I think of it is like having four objects in front of you. You need to hold the first in your hand, then move the last item to the first place, and then place the item in your hand in the last place.
Afterwards, you increase the leftmost side by one and decrease the rightmost side by one:
function reverseArr(arr) {
let lh;
for(let i = 0; i<arr.length/2; i++){
lh = arr[i];
arr[i] = arr[arr.length -i -1];
arr[arr.length -i -1] = lh;
}
return arr;
}
reverseArr([0,1,2,3,4,5,6,7,8,9]);
Like so. I even named my variable lh for "left hand" to help the idea along.
Understanding arrays is massively important, and figuring out how they work will not only save you from unnecessarily long and tedious ways of solving this, but will also help you grasp certain data concepts way better!
I found a way of reversing the array this way:
function reverse(arr){
for (let i = arr.length-1; i >= 0; i--){
arr.splice(i, 0, arr.shift());
}
return arr;
}
Without Using any Pre-define function
const reverseArray = (array) => {
for (let i = 0; i < Math.floor(array.length / 2); i++) {
[array[i], array[array.length - i - 1]] = [
array[array.length - i - 1],
array[i]
];
}
return array;
};
let array = [1,2,3,4,5,6];
const reverse = (array) => {
let reversed = [];
for(let i = array.length - 1; i >= 0; i--){
reversed[array.length - i] = array[i];
}
return reversed;
}
console.log(reverse(array))
you can use the two pointers approach
example
function reverseArrayTwoPointers(arr = [1, 2, 3, 4, 5]) {
let p1 = 0;
let p2 = arr.length - 1;
while (p2 > p1) {
const temp = arr[p1];
arr[p1] = arr[p2];
arr[p2] = temp;
p1++;
p2--;
}
return arr;
}
to return [5,4,3,2,1]
example on vscode
let checkValue = ["h","a","p","p","y"]
let reverseValue = [];
checkValue.map((data, i) => {
x = checkValue.length - (i + 1);
reverseValue[x] = data;
})
function reverse(str1) {
let newstr = [];
let count = 0;
for (let i = str1.length - 1; i >= 0; i--) {
newstr[count] = str1[i];
count++;
}
return newstr;
}
reverse(['x','y','z']);
Array=[2,3,4,5]
for(var i=0;i<Array.length/2;i++){
var temp =Array[i];
Array[i]=Array[Array.length-i-1]
Array[Array.length-i-1]=temp
}
console.log(Array) //[5,4,3,2]

Javascript computing permutations - why is my code returning unwanted solution when I don't make a copy of the array?

Below is code for a function that returns all permutations of a given array.
function getAllPerms(s) {
var perms = [];
if (s.length === 1) {
perms.push(s);
} else {
for (var i = 0; i < s.length; i++) {
var sub = s.slice(0);
sub.splice(i, 1);
var sp = getAllPerms(sub);
for (var o = 0; o < sp.length; o++) {
sp[o].unshift(s[i]);
perms.push(sp[o]);
}
}
}
return perms;
}
console.log(getAllPerms([1,2])); // result is [[1, 2], [2, 1]]
however if i don't make a copy of the array and splice the original array I don't get the same output, and I have been racking my brain to understand why? To me, it seems as though it should work either way. Below is the code with changes to the original array.
function getAllPerms(s) {
var perms = [];
var len = s.length
if (s.length === 1) {
perms.push(s);
} else {
for (var i = 0; i < len; i++) {
var digit = s[i];
s.splice(i, 1);
var sp = getAllPerms(s);
for (var o = 0; o < sp.length; o++) {
sp[o].unshift(digit);
perms.push(sp[o]);
}
}
}
return perms;
}
console.log(getAllPerms([1,2])); // result is [[2, 1], [2, 1]]
For the first set of code I get the correct result,[[1, 2], [2, 1]], but for the second bit of code I get something strange, [[2, 1], [2, 1]]. Cannot for the life of me figure out what is going on.
When you run the code that changes the original array, you're actually modifying the input array sto be first [1,2] then [2,1], and your return array is just the original array s multiple times, so modifying s to become the second element also modifies it as the first element.
You can see the effect more simply by running the following:
var x = [1,2]
var p = []
p.push(x)
x[0] = 2
x[1] = 1
p.push(x)
Observe how x and p change after each line.

Output each combination of an array of numbers with javascript

I have several numbers in an array
var numArr = [1, 3, 5, 9];
I want to cycle through that array and multiply every unique 3 number combination as follows:
1 * 3 * 5 =
1 * 3 * 9 =
1 * 5 * 9 =
3 * 5 * 9 =
Then return an array of all the calculations
var ansArr = [15,27,45,135];
Anyone have an elegant solution? Thanks in advance.
A general-purpose algorithm for generating combinations is as follows:
function combinations(numArr, choose, callback) {
var n = numArr.length;
var c = [];
var inner = function(start, choose_) {
if (choose_ == 0) {
callback(c);
} else {
for (var i = start; i <= n - choose_; ++i) {
c.push(numArr[i]);
inner(i + 1, choose_ - 1);
c.pop();
}
}
}
inner(0, choose);
}
In your case, you might call it like so:
function product(arr) {
p = 1;
for (var i in arr) {
p *= arr[i];
}
return p;
}
var ansArr = [];
combinations(
[1, 3, 5, 7, 9, 11], 3,
function output(arr) {
ansArr.push(product(arr));
});
document.write(ansArr);
...which, for the given input, yields this:
15,21,27,33,35,45,55,63,77,99,105,135,165,189,231,297,315,385,495,693
I think this should work:
var a = [1, 3, 5, 9];
var l = a.length;
var r = [];
for (var i = 0; i < l; ++i) {
for (var j = i + 1; j < l; ++j) {
for (var k = j + 1; k < l; ++k) {
r.push(a[i] * a[j] * a[k]);
}
}
}
Edit
Just for my own edification, I figured out a generic solution that uses loops instead of recursion. It's obvious downside is that it's longer thus slower to load or to read. On the other hand (at least on Firefox on my machine) it runs about twice as fast as the recursive version. However, I'd only recommend it if you're finding combinations for large sets, or finding combinations many times on the same page. Anyway, in case anybody's interested, here's what I came up with.
function combos(superset, size) {
var result = [];
if (superset.length < size) {return result;}
var done = false;
var current_combo, distance_back, new_last_index;
var indexes = [];
var indexes_last = size - 1;
var superset_last = superset.length - 1;
// initialize indexes to start with leftmost combo
for (var i = 0; i < size; ++i) {
indexes[i] = i;
}
while (!done) {
current_combo = [];
for (i = 0; i < size; ++i) {
current_combo.push(superset[indexes[i]]);
}
result.push(current_combo);
if (indexes[indexes_last] == superset_last) {
done = true;
for (i = indexes_last - 1; i > -1 ; --i) {
distance_back = indexes_last - i;
new_last_index = indexes[indexes_last - distance_back] + distance_back + 1;
if (new_last_index <= superset_last) {
indexes[indexes_last] = new_last_index;
done = false;
break;
}
}
if (!done) {
++indexes[indexes_last - distance_back];
--distance_back;
for (; distance_back; --distance_back) {
indexes[indexes_last - distance_back] = indexes[indexes_last - distance_back - 1] + 1;
}
}
}
else {++indexes[indexes_last]}
}
return result;
}
function products(sets) {
var result = [];
var len = sets.length;
var product;
for (var i = 0; i < len; ++i) {
product = 1;
inner_len = sets[i].length;
for (var j = 0; j < inner_len; ++j) {
product *= sets[i][j];
}
result.push(product);
}
return result;
}
console.log(products(combos([1, 3, 5, 7, 9, 11], 3)));
A recursive function to do this when you need to select k numbers among n numbers. Have not tested. Find if there is any bug and rectify it :-)
var result = [];
foo(arr, 0, 1, k, n); // initial call
function foo(arr, s, mul, k, n) {
if (k == 1) {
result.push(mul);
return;
}
var i;
for (i=s; i<=n-k; i++) {
foo(arr, i+1, mul*arr[i], k-1, n-i-1);
}
}
This is a recursive function.
First parameter is array arr.
Second parameter is integer s. Each call calculates values for part of the array starting from index s. Recursively I am increasing s and so array for each call is recursively becoming smaller.
Third parameter is the value that is being calculated recursively and is being passed in the recursive call. When k becomes 1, it gets added in the result array.
k in the size of combination desired. It decreases recursively and when becomes 1, output appended in result array.
n is size of array arr. Actually n = arr.length
var create3Combi = function(array) {
var result = [];
array.map(function(item1, index1) {
array.map(function(item2, index2) {
for (var i = index2 + 1; i < array.length; i++) {
var item3 = array[i];
if (item1 === item2 || item1 === item3 || item2 === item3 || index2 < index1) {
continue;
}
result.push([item1, item2, item3]);
}
});
});
return result;
};
var multiplyCombi = function(array) {
var multiply = function(a, b){
return a * b;
};
var result = array.map(function(item, index) {
return item.reduce(multiply);
});
return result;
}
var numArr = [1, 3, 5, 9];
// create unique 3 number combination
var combi = create3Combi(numArr); //[[1,3,5],[1,3,9],[1,5,9],[3,5,9]]
// multiply every combination
var multiplyResult = multiplyCombi(combi); //[15,27,45,135];
https://github.com/dankogai/js-combinatorics
Found this library. Tested to be working. Below is from the library document:
var Combinatorics = require('js-combinatorics');
var cmb = Combinatorics.combination(['a','b','c','d'], 2);
while(a = cmb.next()) console.log(a);
// ["a", "b"]
// ["a", "c"]
// ["a", "d"]
// ["b", "c"]
// ["b", "d"]
// ["c", "d"]
Using node, you can do this pretty easily using a library. First install bit-twiddle using npm:
npm install bit-twiddle
Then you can use it in your code like this:
//Assume n is the size of the set and k is the size of the combination
var nextCombination = require("bit-twiddle").nextCombination
for(var x=(1<<(k+1))-1; x<1<<n; x=nextCombination(x)) {
console.log(x.toString(2))
}
The variable x is a bit-vector where bit i is set if the ith element is contained in the combination.

Categories

Resources