Subarrays in an array - javascript

I'm quite knew to JavaScript (been studying it only for less than a week now) and am having problems computing the sum of the values in the subarrays I generated from a certain array. I was able to do that using this function:
function getSubs(arr) {
var newarr = [];
for (var i = 0; i < arr.length; i++){
for (var j = arr.length; j > 0; j--){
newarr.push(arr.slice(i, j));
}
}
return newarr;
}
Now if this function was invoked for example for the array [1,2,3], the result is [[], [], [], [1], [2], [3], [2, 3], [1, 2], [1, 2, 3]]. I don't understand why there are three null arrays but this is close to what I'm trying to achieve. Additionally, I want to get the sums of the values in each subarray. I know the code above's very crude. Hope someone can help me improve it. Thanks in advance!

The condition for the nested for is incorrect.
Change it from j > 0 to j > i, and it will work fine:
function getSubs(arr){
var newarr = [];
for (var i=0;i<arr.length;i++){
for (var j=arr.length;j>i;j--){
newarr.push(arr.slice(i,j));
}
}
return newarr;
}
Input:
[1,2,3]
Output:
[[1,2,3],[1,2],[1],[2,3],[2],[3]]
Just to note: considering Array.slice(initialOffset, finalOffset), it makes sense to just return a not empty array when finalOffset > initialOffset.

Related

Reverse Array without Reverse Method - Exercise from Eloquent Javascript Book

I am trying to reverse an array without using reverse method, but am encountering a behavior I do not understand when using pop and push functions together. Can someone explain why I am seeing the result I receive?
function reverseArray(array) {
let newArray = []
array.map((num)=> {
newArray.push(array.pop())
})
return newArray
}
console.log(reverseArray([1, 2, 3, 4, 5]))
Result is
// [object Array] (3)
[5,4,3]
This is driving me nuts, I'm wondering if it is something I'm not understanding with the return values of map, pop or push mutating the original array? This is an exercise from the book Eloquent Javascript, I have reversed an array in other ways before. I want to avoid using a loop if at all possible, so if there are any ideas for how to solve this that do not involve a loop it would be much appreciated.
When you call .pop(), you're mutating the value of array, removing the last element of the array. This prevents you from fully iterating over the entire array. Once you're trying to loop the 4th time, the length of the array is 2 ([1, 2]) which is less than 4 which we would need to access the 3rd index, so it stops iterating. You can either do this using a normal for loop or by copying the array.
function reverseArray(array) {
const newArray = new Array(array.length);
for (let i = 0; i < array.length; i++) {
newArray[array.length-1 - i] = array[i];
}
return newArray;
}
console.log(reverseArray([1, 2, 3, 4, 5]));
or (but this is really weird, don't do this)
function reverseArray(array) {
const copy = array.slice(0);
const newArray = [];
array.forEach((_) => {
newArray.push(copy.pop());
});
return newArray
}
console.log(reverseArray([1, 2, 3, 4, 5]));
I would try something like
while (array.length) {
newArray.push(array.pop());
}
There is no avoiding some kind of loop.
Perhaps, it's easier to just traverse the array from the end:
for (let i = array.length - 1; i >= 0; i--) {
nums.push(array[i]);
}
Or, if you want to use instance methods built in:
for (let i = 0; i < array.length; i++) {
nums.push(array.pop());
}
Alternatively, you could also do it in-place, by swapping the elements:
for (let i = 0; i < Math.floor(array.length / 2); i++) {
const tmp = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = tmp;
}

Finding max value in an array of sub arrays

function largestOfFour(arr) {
let newArr = [];
let max = 0;
for(let i = 0; i<arr.length;i++){
for(let j = 0; j<arr[i].length; j++){
if(arr[i][j]>max){
max = arr[i][j];
console.log(max);
newArr.push(max);
}
}
}
return newArr;
}
Hello I am writing a code to find the max value in an array of sub arrays and am required to add that max value to a new array. My code is above. The problem is my code is pushing every value greater than the max to the new array. When I just want the true max without using the Math.max function. I believe this is happening because I do not have a way of updating the max when a new max is found. Some guidance would be very helpful
Initialize max in the outer loop (i) with -Infinity (the smallest "number" available"), then compare and update it in the inner loop, but only push it after the inner loop is done:
function largestOfFour(arr) {
const newArr = [];
for (let i = 0; i < arr.length; i++) {
let max = -Infinity;
for (let j = 0; j < arr[i].length; j++) {
if (arr[i][j] > max) {
max = arr[i][j];
}
}
newArr.push(max);
}
return newArr;
}
const result = largestOfFour([[4, 3, 2, 1], [1, 2, 3, 4], [500, 600, 400], [300, 1000, 700]]);
console.log(result);
You could save the first value as start value for max and iterate from the second index.
Later push the max value of the nested array to the result array.
function largestOfFour(arrays) {
const maxValues = [];
for (let [max, ...array] of arrays) {
for (const value of array) if (max < value) max = value;
maxValues.push(max);
}
return maxValues;
}
console.log(largestOfFour([[3, 2, 1, 7], [2, 6, 4, 9], [2, 2, 1, 1], [4, 3, 6, 7]]));
From your description of the problem i can understand that you want the maximum value from the subarrays of the array.
In this situation you do not need to use
newArr.push(max) Inside the IF block. You can use this line after the two nested loop are finished. Then you use newArr.push(max);
And then return newarr.

Understanding nested for loops in javascript

I'm learning JavaScript at the moment on freecodecamp and they have an example for nested for loops in one of their excercises:
var arr = [[1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
With console.log = 1 2 3 4 5 6 undefined.
I understand for loops more or less, and I understand that [i] and [j] are used to access the array (I think?). I just don't understand why at the end it just prints out those numbers? I found this question asked a few years back but it just explains how to write them, not how they work:
For loop in multidimensional javascript array
I broke it down into:
var arr = [ [1,2], [3,4], [5,6]];for (var i=0; i < arr.length; i++) {
console.log(arr[i]);}
Which prints out
[ 1, 2 ]
[ 3, 4 ]
[ 5, 6 ]
undefined
and
var arr = [ [1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[i]); }}
which prints out:
[ 1, 2 ]
[ 1, 2 ]
[ 3, 4 ]
[ 3, 4 ]
[ 5, 6 ]
[ 5, 6 ]
undefined
and
var arr = [ [1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
for (var j=0; j < arr[i].length; j++) {
console.log(arr[j]); }}
which prints out
[ 1, 2 ]
[ 3, 4 ]
[ 1, 2 ]
[ 3, 4 ]
[ 1, 2 ]
[ 3, 4 ]
undefined
I understand the first two arr[i]. The loop iterates through the array and prints out the individual elements (in this case an array) and in the second one I guess it just does it twice because there are two loops. What I don't understand is:
why the last array in arr[j] is not printed out (where did the
[5, 6] go?)
why arr[i][j] suddenly eliminates the arrays and just
prints out the numbers
where the 'undefined' comes from
Could anyone help me out with this and explain the steps the code takes before printing it out in the console? I would really like to understand it but don't even know how to search for this question the right way.
var arr = [[1,2], [3,4], [5,6]];
This is an array of arrays. It is a little bit easier to read like this:
var arr = [
[1,2],
[3,4],
[5,6]
];
That makes it a little bit easier to see that you have an array of 3 arrays. The outer 'for' will loop through each of 1st level arrays. So the very first outer for loop when i=0 you are going to grab the first inner array [1,2]:
for (var i=0; i < arr.length; i++) {
//First time through i=0 so arr[i]=[1,2];
}
In the inner loop you are going to loop through each of the 3 inner arrays one at a time.
for (var j=0; j < arr[i].length; j++) {
//Handle inner array.
}
This argument grabs the length of the inner array:
arr[i].length
So on your first time through the outer loop i=0 and arr[i] is going to equal [1,2] because you are grabbing the 0th element. Remember, arrays elements are always counted starting at 0, not 1.
Finally you are printing out the results with:
console.log(arr[i][j]);
The first time through you can break it down a little. i=0 and j=0. arr[0][0] which translates as grab the first element from the outer array and then the first element from the first inner array. In this case it is '1':
[
[1,2], <-- 0
[3,4], <-- 1
[5,6] <-- 2
];
The code will loop through the first first set [1,2], then the second [3,4], and so on.
The double for loop you have above works like so:
var arr = [[1,2], [3,4], [5,6]];
for (var i=0; i < arr.length; i++) {
// i = 0, then we loop below:
for (var j=0; j < arr[i].length; j++) {
//here we loop through the array which is in the main array
//in the first case, i = 0, j = 1, then we loop again, i = 0, j = 1
console.log(arr[i][j]);
//after we finish the stuff in the 'j' loop we go back to the 'i' loop
//and here i = 1, then we go down again, i, remains at 1, and j = 0, then j = 1
//....rinse and repeat,
}
}
In plain english:
We grab the first element in the main array, which is an array itself,
we loop through that, and log at each index, this is terminated by our length condition in the second loop. We then move to to the next index of the main array, which is an array itself.... and so on, until we reach the end of the main array
To access and index in the main array, we need to use array[i] - that index holds an array - so to go INTO that array, we need to use array[i][j]
Hope that makes sense!
Despite some caveats of using for-in loops on arrays, they can imo sometimes help to clear the mess in nested loops a bit:
var arr = [[1,2], [3,4],[5,6]];
for (i in arr){
for (j in arr[i]){
console.log(arr[i][j]);
}
}
Also code visualization can clarify execution!
I know this is an old question... But because this is a popular post from ye olde google search, I feel it's helpful to add a way to visualize what's going on in nested for-loops.
As a JS teacher, I've found this method super helpful for visually-oriented people and those w/ dyslexia and related things).
// Original: https://repl.it/#justsml/nested-loop-visualizations
var nums = [[1,2,3], [4,5,6], [7,8,9]];
console.log('Example w/ Numbers:\n');
console.log('The array data: ', JSON.stringify(nums));
for (var i=0; i < nums.length; i++) {
// Main/"top" array - accessing via "arr[i]"
for (var j=0; j < nums[i].length; j++) {
// here we loop through the "child" arrays
let helpfulLabel = `nums[${i}][${j}]`
let value = nums[i][j]
console.log(helpfulLabel, 'Value=' + value);
}
}
console.log('\nExample w/ String Data:\n');
var letters = [['a', 'b', 'c'], ['d', 'e', 'f'], ['x', 'y', 'z']];
console.log('The array data: ', JSON.stringify(letters));
for (var i=0; i < letters.length; i++) {
for (var j=0; j < letters[i].length; j++) {
let helpfulLabel = `letters[${i}][${j}]`
let value = letters[i][j]
console.log(helpfulLabel, 'Value=' + value);
}
}
Preview of Results
function multiplyAll(arr) {
var product = 1;
// Only change code below this line
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
product *= arr[i][j];
console.log(product)
}
}
// Only change code above this line
return product;
}
// Modify values below to test your code
multiplyAll([[1], [2], [3]])
//multiplyAll([[1, 2], [3, 4], [5, 6, 7]]);
//multiplyAll([[5, 1], [0.2, 4, 0.5], [3, 9]])
why the last array in arr[j] is not printed out (where did the [5,
6] go?)
You may notice that if you print out j as console.log(j), it will
print 6 times as 0, 1, 0, 1, 0, 1. And what you're trying to print
is arr[j] which [5, 6] will not be displayed because its on
arr[2]
why arr[i][j] suddenly eliminates the arrays and just prints out the numbers
As you state there, arr is an array of 3 arrays. arr[i] represents
3 arrays either of [1, 2], [3, 4] or [5, 6]. And the j in
arr[i][j] represents the index of those 3 arrays. This is called
Multidimensional Array. arr[i][j] does not eliminate the array, but It selects the value in the index of j inside arr[i].
where the 'undefined' comes from
It's just chrome thingy when you use console.log. Chrome returns
undefined whenever you try to do that. Try to do it on firefox and you
will see it no longer.
function multiply(arr) {
var product = 1;
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
product *= arr[i][j];
}
}
return product;
}

Removing specific Arrays out of multidimensional arrays

I have this array, but not in any guaranteed order:
[ [2,1], [2,2], [2,3], [3,1], [3,2], [4,1], [4,2], [4,3], [4,4], [5,1], [5,2] ]
I need to cycle through it, match the ones with the same arr[0] value, and then remove the one with the highest value at arr[1]. It should end up looking like this:
[ [2,1], [2,2], [3,1], [4,1], [4,2], [4,3], [5,1] ]
I'm not sure exactly how to iterate through this accurately. Most places I have seen ways to filter complex objects, or remove single values from one-dimensional arrays.
I have only really gotten into using arrays in the last few days. Thanks for the help!
Okay I have two solutions. version1 is basic and could use some optimizing while version2 should be faster with bigger, evenly distributed lists.
If you're only going to have a few items, use one. It only has a few lines of code, so it won't be a distraction. If you have a big array and it'll be pretty evenly distributed, then use two.
I actually did a test with the sample data, and version2 has less iterations than version1. V1 ran 11 times in the outer loop, and 79 times in the inner loop. V2 ran 11 times in the first outer loop, 4 times in the second one. The inner loop of the second loop ran 11 times, and the loop inside that ran only 7 times. So the total iterations of v2 was about 40% of v1. When I double the items, v2 only uses 30% of the iterations.
Version2 has a couple of other potential advantages.
I believe Array.push has a higher performance cost than Array[index] =. If that's true, then you know that newAry will have a final length of the origianl array's length - the length of the indicies array length. So you can initialize newAry with that length, keep a counter variable, and then do something like newAry[counter++] = someVal.
There was some discussion if you wanted to keep a result if there was only one. If that is the case, it is easy to do a check at the start of the second loop: if (iVal.length == 1) // add to newAry else do j,k loops.
Version 1
function version1(ary) {
var newAry = [];
var iVal, jVal;
for (var i = 0, il = ary.length; i < il; i++) {
iVal = ary[i];
for (var j = ary.length - 1; j >= 0; j--) {
if (i != j) {
jVal = ary[j];
if (iVal[0] == jVal[0] && iVal[1] < jVal[1]) {
newAry.push(iVal);
break;
}
}
}
}
return newAry;
}
Version 2
function version2(ary) {
var indices = [];
var values = [];
var newAry = [];
var iVal,
index,
highestFound,
lowFound;
for (var i = 0, il = ary.length; i < il; i++) {
var iVal = ary[i];
if ((index = indices.indexOf(iVal[0])) == -1) {
indices.push(iVal[0])
values.push([ iVal[1] ]);
index++;
}
else {
values[index].push(iVal[1])
};
}
for (var i = 0, il = values.length; i < il; i++) {
iVal = values[i];
highestFound = false;
for (var j = 0, jl = iVal.length; j < jl; j++) {
if (!highestFound) {
lowFound = false;
for (var k = j + 1, kl = iVal.length; k < kl; k++) {
if (iVal[j] < iVal[k]) {
lowFound = true;
newAry.push([indices[i], iVal[j]]);
k = kl;
}
}
if (!lowFound) {
highestFound = true;
}
}
else {
newAry.push([indices[i], iVal[j]]);
}
}
}
return newAry;
}
jsFiddle
jsFiddle with Counters
Based on what you've given so far, here's the code I came up with:
var foo = [
[2, 1],
[2, 2],
[2, 3],
[3, 1],
[3, 2],
[4, 1],
[4, 2],
[4, 3],
[4, 4],
[5, 1],
[5, 2]
],
temp = [];
foo.forEach(function (value, index) {
if (typeof temp[value[0]] === 'undefined') {
temp[value[0]] = {
highestValue: value[1],
position: index
};
} else {
if (temp[value[0]].highestValue < value[1]) {
temp[value[0]].highestValue = value[1];
temp[value[0]].position = index;
}
}
});
temp.forEach(function(value, index) {
delete foo[value.position];
});
Do note that if you have in foo for instance [6,1], it will be deleted as well.
Making use of the excellent lodash.js library:
var ary = [ [2,1], [2,2], [2,3], [3,1], [3,2], [4,1], [4,2], [4,3], [4,4], [5,1], [5,2] ];
var results = _(ary)
// Group by the first value
.groupBy(function(pair) {
return pair[0];
})
// Turn the groups into arrays
.map(function(group) {
// Sort by the second value
var sorted = _.sortBy(group, function(pair) {
return pair[1];
});
// Keep all but the highest value
return _.take(sorted, sorted.length-1);
})
// Remove the groupings
.flatten(true)
// Unwrap the results
.value();
console.log(results);
jsFiddle: http://jsfiddle.net/dmillz/BhSDT/
I hope that helps!

Javascript Array.push method issue

I have the following code:
function build_all_combinations(input_array){
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0]
array.push(push_value)
console.log(array)
combo.push(array)
}
console.log(combo)
}
Which outputs:
[2, 3, 1]
[3, 1, 2]
[1, 2, 3]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
The last line should be: [[2, 3, 1],[3, 1, 2],[1, 2, 3]]
I'm obviously not grokking something about the way the array is working. Each individual array is correct, but when I go to push them to the combo array, something is failing along the way. What is it?
Each time you are pushing the same array into the combo array; ie, all the references are pointing to the same instance in memory. So when you update one, you've in reality updated them all.
If you want separate references, you'll need to create separate arrays.
shift and slice are your friends here:
var array = [1,2,3];
var combo = []
for(var i = 0; i<array.length; i++){
array.push(array.shift()); // remove first element (shift) and add it to the end (push)
combo.push(array.slice()); // add a copy of the current array to combo
}
DEMO
jordan002 has given the explanation for this behaviour.
Here's the workaround.
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0];
array.push(push_value);
console.log(array);
combo.push(array.concat([]));
}
console.log(combo);
You can store a copy in temp variable.
array = [1,2,3]
limit = array.length - 1
combo = []
for(i = 0; i<= limit; i++){
splice_value = array.splice(0,1)
push_value = splice_value[0];
array.push(push_value);
console.log(array);
var temp = array.slice();
combo.push(temp);
}
console.log(combo)
Reference

Categories

Resources