Multi-dimensional For Loop - javascript

I have three arrays and I need to create a set of rules based on these three arrays, but I'm struggling with the logic of how to write a function that will give me every possible combination of every entry in each array. So, I have, for example:
var array 1 = [1, 2];
var array 2 = [3, 4, 5];
var array 4 = [6, 7, 8, 9, 10];
And I'd wan't get back a string, object etc of all possible combinations (which I wont attempt to work out here). So for example:
var result = ["1-3-6", "2-3-6", "1,4,6"];
And so on, so far I've tried sitting down and composing a For Loop but I'm just really not sure where to start. I also looked at maps, but could not find any examples that went this deep, so I wasn't sure if a map would get the job done either.
The actual data I want to load in, the first array has 2 entries, the second have 7 and the last one had 6, so for the workings out I've done there should be 84 entries. That was based on (Array 3 * Array 2) * Array 1.
Hope that all makes sense I know it's a bit confusing. Also worth mentioning that I'm using Angular JS so an angular solution or vanilla JS solution is preferred but not essential.

What you are looking is the Cartesian product of arrays. You can use a function like this (extracted from here):
function cartesian() {
var r = [], arg = arguments, max = arg.length-1;
function helper(arr, i) {
for (var j=0, l=arg[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(arg[i][j]);
if (i==max)
r.push(a);
else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
There are lot of examples, like:
JavaScript - Generating combinations from n arrays with m elements
With recursive:
Finding All Combinations of JavaScript array values
Cartesian product of multiple arrays in JavaScript
And with multiple (N) arrays:
Combine 2 arrays into 1 in all possible ways in JavaScript
Hope it helps!

Nested for loops will do
function arrComb(arr1, arr2, arr3) {
var l1 = arr1.length,
l2 = arr2.length,
l3 = arr3.length,
i, j, k, res = [];
for (i = 0; i < l1; i++) {
for (j = 0; j < l2; j++) {
for (k = 0; k < l3; k++) {
res.push(arr1[i] + '-' + arr2[j] + '-' + arr3[k]);
}
}
}
console.log(res)
}
arrComb([1, 2], [3, 4, 5], [6, 7, 8, 9, 10]);

A bit more elegant:
var array_1 = [1, 2];
var array_2 = [3, 4, 5];
var array_4 = [6, 7, 8, 9, 10];
var result = [];
for (var a1 of array_1)
{
for (var a2 of array_2)
{
for (var a3 of array_4)
{
result.push("\""+a1+"-"+a2+"-"+a3+"\"")
}
}
}
alert("["+result+"]")

Related

Is this considered a selection sort?

I was practicing a while ago and came across selection sort. After some research across difference sources, there are some that declare an array then delete the current min location while others swap within the array
I tried to use ES6 for some trivial functions, did not use map since I wanted to understand the loop on a whiteboard.
Is this considered a selection sort?
selectionSortNoSwap = list)= => {
const result = [];
for (let i = 0; i < list; i++) {
const min = Math.min(...list);
const minIndex = list.indexOf(min);
result.push(min);
list.splice(minIndex, 1);
}
return result;
};
selectionSortNoSwap([3, 5, 2, 1, 4]);
Thank you
No. True selection sort sorts in-place, rather than creating another array. That is, given:
[3, 5, 2, 1, 4]
after the first iteration, a selection sort should produce the following data structure in memory:
[1, 5, 2, 3, 4]
where the 1 and 3 have been exchanged - and not
[3, 5, 2, 4]
[1]
If elements are not swapped with each other, it's not selection sort.
To sort in-place, you'd need something like
const selectionSort = (list) => {
for (let i = 0; i < list.length; i++) {
// for convenience - or use a for loop
const min = Math.min(...list.slice(i));
const minIndex = list.indexOf(min, i);
[list[i], list[minIndex]] = [list[minIndex], list[i]];
}
return list;
};
console.log(selectionSort([3, 5, 2, 1, 4]));

Identical for loop doesn't seem to be working

I'm trying to solve a coding challenge from Free Code Camp.
Diff Two Arrays
Compare two arrays and return a new array with any items only found in one of the two given arrays, but not both. In other words, return the symmetric difference of the two arrays.
[1, 2, 3, 5], [1, 2, 3, 4, 5] should return [4].
[1, "calf", 3, "piglet"], [1, "calf", 3, 4] should return ["piglet", 4].
My code is below:
function diffArray(arr1, arr2) {
var arr1Key = [];
arr1Key = arr1;
for (i = arr1.length - 1; i >= 0; i--) {
for (j = 0; j < arr2.length; j++) {
if (arr1[i] === arr2 [j]) {
arr1.splice(i, 1);
}
}
}
for (k = arr2.length - 1; k >= 0; k--) {
for (l = 0; l < arr1Key.length; l++) {
if (arr2[k] === arr1Key[l]) {
arr2.splice(k, 1);
}
}
}
var newArr = [];
newArr = arr1.concat(arr2);
return (newArr)
}
diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
I know it's probably not perfect/optimal, but what I primarily want to know is why my first series of for loops (using i & j) works perfectly. Meanwhile, my next series of for loops (using k & l) is a nearly identical copy of the first, but after some testing I found that only the k for loop works. The l for loop isn't working, and I don't understand why.
I've been staring at this thing and tinkering with it for what feels like forever and I just don't understand.
You are splicing the arrays while looping through them, splicing can make them grow or shrink and you don't want that because you are using the array's length to loop.
The problem is that you think you clone arr1 by writing arr1Key = arr1;
This does not clone but creates a reference to arr1, so arr1.splice(i, 1); changes also arr1Key.
Just change the line arr1Key = arr1; into arr1Key = arr1.slice();

Dividing numbers between each other in a Javascript array

I have an array of randomly generated numbers.
I want to create a function that divides all those numbers. Basically, assuming that I have 5 numbers in the array [5, 7, 6, 8, 2], I want the output to be equal to 5 / 7 / 6 /8 / 2
array = [5, 7, 6, 8, 2];
var total = 1;
for(var i = 0; i < array.length; i++) {
total = array[i] / total;
}
return total;
This is what I did so far, but the output isn't the correct one. Any idea where I am doing wrong?
You've basically got your math backwards. With your approach, you want to progressively divide total, rather than progressively dividing by total.
var total = array[0];
for (var i = 1; i < array.length; i++)
total = total / array[i];
return total;
Try this. It uses the array's reduce method along with es6 arrow functions which makes it a one liner. You can use babel to convert es6 syntax to es5.
var arr = [5, 7, 6, 8, 2];
arr.reduce((prev,curr) => prev/curr);
ES5 version:
var arr = [5, 7, 6, 8, 2];
arr.reduce(function(prev, curr) {
return prev/curr;
});
As you can see in the docs, Array.reduce() will reduce a list of values to one value, looping through the list, applying a callback function and will return a new list. In that callback you can access four parameteres:
previousValue: If you pass an argument after callback function, previousValue will assume that value, otherwise it'll be the first item in array.
currentValue: The current value in the loop.
index: Index of the current item on loop.
array: The list
Well you messed up with the total, you kept dividing each new number with the result. You just have to flip the '/' operators.
array = [5, 7, 6, 8, 2];
var total = array[0];
for(var i = 1; i < array.length; i++) {
total = total/array[i];
}
return total;
Try this ...
array = [5, 7, 6, 8, 2];
var total = array[0];
for(var i = 1; i < array.length; i++) {
total = array[i] / total;
}
return total;

Comparing values in multiple arrays

I have two arrays where I need to compare values and get the duplicates. I wrote most of the code but seem to be stumped on the comparison.
Here is my code:
function compare(arr1, arr2) {
for (var i = 0; i< arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
console.log[i];
}
}
}
}
compare([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
I get the for loops to print all of the numbers, but for some reason the if statement comparison doesn't work. Is there something I am not getting about comparing values in arrays?
I am not looking for a straight up answer but guidance if possible.
Your code is quadratic in time since it iterates the second array for each item in the first array. A linear time solution is to convert the first array into a hash table, and then, for each item in the second one, instantly check if it is in the hash.
function intersect(a, b) {
var hash = {};
a.forEach(function(x) { hash[x] = 1 });
return b.filter(function(x) { return hash[x] === 1 });
}
c = intersect([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
document.write(c)
Do note, however, that this only works if items to compare are primitives, you cannot put objects in a hash, so the code has to be quadratic:
function intersect(a, b) {
return a.filter(function(x) {
return b.indexOf(x) >= 0
});
}
a = {x:'a'};
b = {x:'b'};
c = {x:'c'};
d = {x:'d'};
i = intersect([a,b,c], [a,b,d]);
document.write(JSON.stringify(i));
Regarding your bit about improving your current code, I suggest that you make your javascript more idiomatic, in particular,
get used to iteration methods instead of for loops
check the repertoire of built-in functions and use them wherever possible
and, for sanity's sake, never ever use ==

Best way to return duplicate elements in an Array

Here is the way I am using to return duplicate elements.. But I am facing most dangerous performance issues like browser close etc when my array have large number of items with long texts..
var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7];
var sorted_arr = arr.sort();
var results = [];
for (var i = 0; i < arr.length - 1; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
results.push(sorted_arr[i]);
}
}
alert(results);
Please suggest me a best way of doing this
i don't get exactly what you want, but if you need to return duplicates you could use a cache object. this works with number or string or whatever.
var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7];
var cache = {};
var results = [];
for (var i = 0, len = arr.length; i < len; i++) {
if(cache[arr[i]] === true){
results.push(arr[i]);
}else{
cache[arr[i]] = true;
}
}
console.log(results);//returns an array with 9 and 4
Of course you can do other things like deleting multiple items etc. etc.
EDIT - i've written a blog entry on how to remove duplicates from an array
If you have array filter, you also have indexOf and lastIndexOf,
and you can return the duplicates without doing the sort.
var results, arr= [9, 9, 111, 2, 3, 4, 4, 5, 4, 7];
if(arr.filter){
results= arr.filter(function(itm, i){
return arr.lastIndexOf(itm)== i && arr.indexOf(itm)!= i;
});
}
else// use your loop method
alert(results)
/* returned value: (Array)
9,4
*/
Assuming Nicola's solution doesn't work for you (since it uses about as much memory as the original solution: two elements stored per element in the input, worst-case), you can use the slower process of repeatedly searching your input.
This requires the Array.indexOf method from ECMAScript 5. A lot of browsers have it. For alternatives, see How do I check if an array includes an object in JavaScript?.
var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7];
var results = [];
for (var i = 0, len = arr.length - 1; i < len; i++) {
if((results.indexOf(arr[i]) == -1) && (arr.indexOf(arr[i], i + 1) != -1)) {
results.push(arr[i]);
}
}
console.log(results);
This uses no more memory than the input arr plus the output results, but it's an O(N^2) algorithm and doesn't have to modify arr.
Your method relies on a sort, which may or may not be one reason you run out of space/time.
The canonical way to remove duplicates is to keep a hash map of the keys (an object in JS). The object keys you get back won't necessarily be in the order you want; you don't specify if you want the results ordered as well, but they are now.
You could null out the original array, since you no longer require it; when it gets collected is up to the JS engine though.
You could remove duplicates "in place" by keeping a "current index" into the sorted array, and increment it only when you move a non-duplicated element "down" from the counter index, then truncate the array that you return.
Combining the last two techniques should mean that in general you'll only have a single array with a valid reference.
Edit Example. Setting length explicitly, as .slice() creates a new array.
var have = {};
var arr = [9, 9, 111, 2, 3, 4, 4, 5, 7];
arr = arr.sort();
for (var rIdx = 0, i = 0; i < arr.length; i++) {
if (have[arr[i]]) {
arr[rIdx++] = arr[i];
} else {
have[arr[i]] = true;
}
}
arr.length = rIdx;
console.log(arr);

Categories