JavaScript Programming variables in a for loop - javascript

I'm using a JSON array that has 38 fields and I have to sum each of the fields.
I've tried a small sample set to test how and I'm running into a problem:
I have variables called field1, field2, .... So I figured out how to create them but it looks like it sees the variables as text not the values inside them.
test1 = [[36,1500,2,3,4],[36,15,2,7,8],[36,3000,4,5,6],[36,8,7,6,15]]
for (var i = 0; i < test1.length; i++) { //get each array
for (var n = 0; n < 5; n++) { //get each item in the array
var theField = "field" + n;
theField = theField +test1[i][n]; //This fails
field2 = field2 + test1[i][2]; //This works
If I use field + n to create the variable, the sum value at the end is 0,
if I call field2 = field2 + test1[i][2] at the end of the loop I have the sum for the third value in each array. However I have to hard code field1 -> field38.

Sum by Array
let data = [
[36, 1500, 2, 3, 4],
[36, 15, 2, 7, 8],
[99, 99, 99, 99 ,99], // fake data
[36, 3000, 4, 5, 6],
[36, 8, 7, 6, 15]
]
// only pull records with 36 as value of first element
let filtered = data.filter(arr=>arr[0]==36)
// iterate over each array and sum elements at index 1...end
let sum = filtered.map(([_,...arr]) => arr.reduce((sum, val) => sum += +val, 0))
console.log(sum)
Filter the data for what you want based on the first element (stored in filtered)
Iterate over the remaining array using map(), which will return an array
Inside the map() loop, iterate over each value using reduce() to sum each element of the array
The first element is ignored using destructuring assignment/rest. The [_,...arr] means the first element will be stored in a variable called _, the rest of the elements will be stored in an array called arr, which is elements 2..5 (index:1..4).
Sum by Index
let data = [
[36, 1500, 2, 3, 4],
[36, 15, 2, 7, 8],
[99, 99, 99, 99, 99], // fake data
[36, 3000, 4, 5, 6],
[36, 8, 7, 6, 15]
]
// only pull records with 36 as value of first element
let filtered = data.filter(arr => arr[0] == 36)
// initialize array to hold sums
let sums = Array(filtered[0].length).fill(0)
// iterate over each array and each index to sum value at the index
filtered.forEach(([_, ...arr]) =>
arr.forEach((val, ndx) =>
sums[ndx] += +val
)
)
console.log(sums)
Filter the data for what you want based on the first element (stored in filtered)
Initialize the holding array of sums by index to 0
Iterate over the filtered array (rows) using forEach
Inside the forEach() loop, iterate over each value using another forEach() using the index and value to store to the sums array created earlier
The first element is ignored using destructuring assignment/rest. The [_,...arr] means the first element will be stored in a variable called _, the rest of the elements will be stored in an array called arr, which is elements 2..n (index:1..n-1).

What are you trying to do? If you are trying to sum the arrays.
const test1 = [[36,1500,2,3,4],[36,15,2,7,8],[36,3000,4,5,6],[36,8,7,6,15]];
const sum = arr => arr.reduce((total, item) => total + item, 0);
console.log(test1.reduce((total, arr) => sum(arr) + total, 0));

You can simply use map to map the array to a new array of sums using reduce to create a sum of the child arrays. This will give an array of sums, if you would like a sum of those, you can then use reduce again on that result and get a final number.
// Our starting data
let test1 = [[36,1500,2,3,4],[36,15,2,7,8],[36,3000,4,5,6],[36,8,7,6,15]]
// a simple reusable sum function
const sum = (sum, val) => sum + val
// Sum each array
let result = test1.map(arr => arr.reduce(sum, 0))
// Display the results (stringified for readability)
console.log('Each array sumed:', JSON.stringify(result))
// Sum the results if needed
console.log('Sum of all arrays:', result.reduce(sum, 0))

Related

Storing the quantity of values from an array into another array

I have got two arrays, one containing values with duplicates and the other empty:
let cart = [7, 7, 15, 21];
let quantity = [];
How can I get the number of times the values occur in the cart array and push it to the quantity array thus getting a result like this:
quantity = [2, 1, 1]
Where:
7 in the cart array is 2 in the quantity array, 15 and 21 is 1 in the quantity array respectively.
You can use a Map to keep the number of times item appeared in the cart and then use it to get the array in the form required
const cartItemsMap = new Map();
let cart = [7, 7, 15, 21, 7];
cart.forEach(item => cartItemsMap.set(item, (cartItemsMap.get(item) || 0) + 1));
let quantity = [...cartItemsMap.values()];
console.log(quantity); // [3, 1, 1] in the same order as of your cart items
We cannot use object here because the object won't keep the keys in order which I suppose you would want
An approach with a closure over an object for keeping indices.
const
cart = [7, 7, 15, 21],
result = [];
cart.forEach((indices => v => {
if (v in indices) result[indices[v]]++;
else indices[v] = result.push(1) - 1;
})({}));
console.log(result);
You can use .reduce to iterate over the cart while using a Map to store the number of occurrences of each number. In the end, you would return the values of this map:
const getOccurences = (cart=[]) =>
cart.reduce((quantity,num) => {
const count = 1 + (quantity.get(num) || 0);
quantity.set(num, count);
return quantity;
}, new Map).values();
console.log( ...getOccurences([7, 7, 15, 21, 7]) );

Index Values SumUp to Total

I am trying to improve in my Problem Solving Skills and would love to get some explanation on what it is that I am doing wrong or if I can get a hand in the right direction. My code below is what I am stuck on.
My problem, I am trying to check within the array if it contains any numbers that will sum up to a total given value. Pretty simple but a bit complex for a beginner.
My first Step is to setup a function with two parameters that accept the array and total amount we want.
const array = [10, 15, 7, 3];
function sumUpTotal(array, total) {
}
Then I want to iterate through my array to check each value within the array by using the forEach method to output each value
const array = [10, 15, 7, 3];
function sumUpTotal(array, total) {
array.forEach(value => value)
}
Now that I have all the outputs, I am stuck on how I can check if the numbers add up with each other to give out the total we want. Can someone please help.
The Output should be two numbers that add up to the total.
For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17.
Using forEach() to iterate over each value in the array and includes() to check if any values further ahead in the array sum to your total you can generate an array of unique sum pairs. By only looking forward from the given iteration one avoids generating duplicate pairings. (eg. avoids [[10, 7], [7, 10]] for you example input)
forEach() provides both the value and the index of the current iteration, which makes it simple to use the optional, second fromIndex argument of includes() to only look ahead in the array by passing index+1. If a match is found an array of [value, difference] is pushed to the result array. The return value is an array of sum pairs, or an empty array if there are no matches.
const array = [10, -2, 15, 7, 3, 2, 19];
function sumUpTotal(array, total) {
let result = []
array.forEach((value, index) => {
let diff = total - value;
if (array.includes(diff, index + 1)) result.push([value, diff]);
});
return result;
}
console.log(JSON.stringify(sumUpTotal(array, 17)));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this using a Set as follows:
function sumUpTotal(array, total) {
// initialize set
const set = new Set();
// iterate over array
for(let i = 0; i < array.length; i++){
// get element at current index
const num = array[i];
// get the remaining number from total
const remaining = total - num;
// if the remaining is already stored in the set, return numbers
if(set.has(remaining)) return [num, remaining];
// else add number to set
else set.add(num);
}
// return null if no two numbers in array that sum up to total
return null;
}
const array = [10, 15, 7, 3];
const total = 17;
console.log( sumUpTotal(array, total) );

JavaScript: Rearrange an array in order – largest, smallest, 2nd largest, 2nd smallest, 3rd largest, 3rd smallest,

Given an array of integers, where the values should be sorted in the following order:
if we have an array
[1, -1, -3, 9, -2, -5, 4, 8,]
we must rearrange it this way: largest number, smallest number, 2nd largest number, 2nd smallest number, ...
[9, -5, 8, -3, 4, -2, 1, -1 ]
I get the first largest and smallest numbers, but can't figure out how to make it dynamic for all values in the array.
I know that I must take two variables, say firstSmallest and firstLargest and point them to the first and last index of the array respectively, run a loop, which I do already in the code below, and store value into new array by incrementing firstSmallest and decrementing firstLargest, but couldn't implement into code.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a-b);
let firstSmallest = sorted[0];
let firstLargest = sorted[unsorted.length-1];
for(let i = 0; i <= sorted.length; i++){
//I should increment firstSmallest and decrement firstLargest numbers and store in output
}
return output;
}
meanderArray(unsortedArr);
console.log(output);
You could take a toggle object which takes the property of either the first item or last from an array and iterate until no more items are available.
function meanderArray([...array]) {
const
result = [],
toggle = { shift: 'pop', pop: 'shift' };
let fn = 'shift';
array.sort((a, b) => a - b);
while (array.length) result.push(array[fn = toggle[fn]]());
return result;
}
console.log(...meanderArray([1, 5, 8, 7, 6, -1, -5, 4, 9, 5]));
You can sort an array by descending, then logic is the following: take first from start and first from end, then second from start-second from end, etc.
let unsortedArr = [1, 5, 8 , 7, 6, -1, -5, 4, 9, 5]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => b-a);
let output = []
for(let i = 0; i < sorted.length/2; i++){
output.push(sorted[i])
if(i !== sorted.length - 1 - i){
output.push(sorted[sorted.length - 1 - i])
}
}
return output;
}
let result = meanderArray(unsortedArr);
console.log(result);
You can sort, then loop and extract the last number with pop() and extract the first number with shift().
let unsortedArr = [1, -1, -3, 9, -2, -5, 4, 8,]
let output = [];
function meanderArray(unsorted){
let sorted = unsorted.sort((a, b) => a - b);
for(let i = 0; i < unsortedArr.length + 2; i++){
output.push(sorted.pop());
output.push(sorted.shift());
}
console.log(output);
return output;
}
meanderArray(unsortedArr);
Fastest Meandering Array method among all solutions mentioned above.
According to the JSBench.me, this solution is the fastest and for your reference i have attached a screenshot below.
I got a different approach, but i found that was very close to one of above answers from elvira.genkel.
In my solution for Meandering Array, First I sorted the given array and then i tried to find the middle of the array. After that i divided sorted array in to two arrays, which are indices from 0 to middle index and other one is from middle index to full length of sorted array.
We need to make sure that first half of array's length is greater than the second array. Other wise when applying for() loop as next step newly created array will contains some undefined values. For avoiding this issue i have incremented first array length by one.
So, always it should be firstArr.length > secondArr.length.
And planned to create new array with values in meandering order. As next step I created for() loop and try to push values from beginning of the first array and from end of the second array. Make sure that dynamically created index of second array will receive only zero or positive index. Other wise you can find undefined values inside newly created Meandering Array.
Hope this solution will be helpful for everyone, who loves to do high performance coding :)
Your comments and suggestions are welcome.
const unsorted = [1, 5, 8, 7, 6, -1, -5, 4, 9, 5];
const sorted = unsorted.sort((a,b)=>a-b).reverse();
const half = Math.round(Math.floor(sorted.length/2)) + 1;
const leftArr = sorted.slice(0, half);
const rightArr = sorted.slice(half, sorted.length);
const newArr = [];
for(let i=0; i<leftArr.length; i++) {
newArr.push(leftArr[i]);
if (rightArr.length-1-i >= 0) {
newArr.push(rightArr[rightArr.length-1-i]);
}
}

How to extract values with the same key from array and compute their average?

so I have a few arrays for different datasets that look similair to this one:
[["zufrieden",10],
["beschämt",24],
["gelangweilt",50],
["begeistert",28],
["unsicher",27],
["niedergeschlagen",49],
["verärgert",72],
["frustriert",29],
["entspannt",25],
["unsicher",27],
["unsicher",31],
["schuldig",22],
["frustriert",18],
["gelangweilt",73],
["wütend",30],
["verlegen",50],
["besorgt",25],
["schwermütig",0]]
How can i get, for example, the average value of all entries with "schuldig".
Also, I need to do this for every single key that is represented by a string in this case.
I tried converting the array to an object and go from there, but I'm stuck and would appreciate any help.
I already came as far counting the occurences of the different strings using the map function.
var counts = {};
orderedFeelings.forEach(function(x) { counts[x] = (counts[x] || 0)+1; });
var countsValues = Object.keys(counts).map(function(key){ return counts[key] });
This is okay for my intent to visualize the data as it returns a list of the occurences, but in order to create a detailed graph, I need to have the average value of all values with the same keys. This is where I'm completely stuck.
All information in one object, with just one iteration O(n):
var arr = [
["zufrieden", 10],
["beschämt", 24],
["gelangweilt", 50],
["begeistert", 28],
["unsicher", 27],
["niedergeschlagen", 49],
["verärgert", 72],
["frustriert", 29],
["entspannt", 25],
["unsicher", 27],
["unsicher", 31],
["schuldig", 22],
["frustriert", 18],
["gelangweilt", 73],
["wütend", 30],
["verlegen", 50],
["besorgt", 25],
["schwermütig", 0]
]
var average = {}
arr.map(o => {
if (o[0] in average) {
average[o[0]][0] += o[1]
average[o[0]][1]++
average[o[0]][2] = average[o[0]][0] / average[o[0]][1]
} else {
average[o[0]] = []
average[o[0]].push(o[1]);//<-- Name
average[o[0]].push(1);//<-- Quantity
average[o[0]].push(o[1] / 1);//<-- Average
}
})
console.log(average.schuldig[2])//<-- Average
console.log(average)
The key is always calculate the average, at the end, we have the real average.
you can use filter method of array
const newArray = this.array.filter(temp => temp[0] === 'schuldig');
var total = 0;
for (each of newArray) {
total += each[1];
}
const avg = (total/newArray.length);
This will give you average the wayx you need it
If you have a predefined format of your dataset like at the first index of each array will be the text and at the second index of array will be the value then you can compute the average by this
function computeAvg(dataset,key) {
let desiredElements = dataset.filter(item => item[0] === key);
return (desiredElements.reduce((sum, current) => sum + current[1],0))/desiredElements.length;
}
let dataset = [["zufrieden",10],
["beschämt",24],
["gelangweilt",50],
["begeistert",28],
["unsicher",27],
["niedergeschlagen",49],
["verärgert",72],
["frustriert",29],
["entspannt",25],
["unsicher",27],
["unsicher",31],
["schuldig",22],
["frustriert",18],
["gelangweilt",73],
["wütend",30],
["verlegen",50],
["besorgt",25],
["schwermütig",0]];
let average = computeAvg(dataset,'schuldig');
You can group all the entries by key with Array.prototype.reduce while counting total sum and their amount, and then go through grouped object and calculate averages:
var data=[["zufrieden",10],["beschämt",24],["gelangweilt",50],["begeistert",28],["unsicher",27],["niedergeschlagen",49],["verärgert",72],["frustriert",29],["entspannt",25],["unsicher",27],["unsicher",31],["schuldig",22],["frustriert",18],["gelangweilt",73],["wütend",30],["verlegen",50],["besorgt",25],["schwermütig",0]];
var grouped = data.reduce((all, [key, val]) => {
if (!all[key]) all[key] = {sum: 0, count:0}
all[key].count++;
all[key].sum += val;
return all;
},{});
var averages = Object.keys(grouped).reduce((all, k) => {
all[k] = parseInt(grouped[k].sum / grouped[k].count);
return all;
}, {});
console.log(averages.zufrieden);
console.log(averages.unsicher);
loop through your data, use array's filter function and compare your current object's [0] index with filters object's [0] index. Now you have matched elements, now use array's reduce method to calculate sum for current key i.e 'zufrieden' and then divide its value by the length of matched array and push that value in current iteration of outer loop i.e 'x'
const data = [
["zufrieden", 10],
["beschämt", 24],
["gelangweilt", 50],
["begeistert", 28],
["unsicher", 27],
["niedergeschlagen", 49],
["verärgert", 72],
["frustriert", 29],
["entspannt", 25],
["unsicher", 27],
["unsicher", 31],
["schuldig", 22],
["frustriert", 18],
["gelangweilt", 73],
["wütend", 30],
["verlegen", 50],
["besorgt", 25],
["schwermütig", 0]
];
/*
loop through your data, use array's filter function and compare your current object's [0] index with filters object's [0] index. Now you have matched elements, now use array's reduce method to calculate sum for current key i.e 'zufrieden' and then divide its value by the length of matched array and push that value in current iteration of outer loop i.e 'x'
*/
data.forEach(x => {
const matched = data.filter(y => y[0] == x[0]);
x.push(matched.map(z => z[1]).reduce((a, b) => a + b, 0) / matched.length);
});
console.log(data);

Join multiple arrays of order indexes

I have multiple arrays of indexes, representing an order:
[[0,1,2], [2,0,1], [1,2,0], [0,1,2], ...]
I need to construct a new array of indexes with a length equal to the total number of indexes in the input while ordering the values using the position indicated in each array in the input.
This would be the output of the input above:
[0, 1, 2, 5, 3, 4, 7, 8, 6, 9, 10, 11, ...]
The total length is 12, so the list of indexes will contain 0-11
The first array of the input is 0, 1, 2 so the output starts with 0, 1, 2
The second array of the input is 2, 0, 1 and the next 3 indexes in the new list are 3-5. ordering these using the second array of the input results in 5,3,4
And so on...
You could use Array#reduce, Array#forEach and the length of the actual array for the count. Then push the sum of all length until now and the value of inner array to the result set.
var array = [[0, 1, 2], [2, 0, 1], [1, 2, 0], [0, 1, 2]],
result = [];
array.reduce(function (r, a) {
a.forEach(function (b) {
result.push(r + b);
});
return r + a.length;
}, 0);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I'm confused by your example, but it sounds like you want to flatten your array by one level. You can do so like this:
var arrays = [[0,1,2], [2,0,1], [1,2,0], [0,1,2]];
var result = [].concat.apply([], arrays);
console.log(result);
If you're using a library like Underscore, there are built-in methods to do that, like the flatten method.
The input and output examples are confusing, but I think what you want it this:
var array = [...] // your array
var result = Array.prototype.concat.apply([], array);
I believe that I interpreted your question based on the expected output, and edited the question accordingly.
You'll need to loop over the sub-arrays in the input and get the next set of indexes for the output, then add those to the output using the order of the sub-array.
This seems to do the trick:
var input = [[0, 1, 2], [2, 0, 1], [1, 2, 0], [0, 1, 2]];
var output = [];
// add values to the output for each of the inputs
$.each(input, function (index, value) {
// get the next and last values to add
var startIndex = output.length;
var lastIndex = (startIndex + value.length) - 1;
// make an array of sequential values from startIndex to lastIndex
var arrayToAdd = [];
for (var i = startIndex; i <= lastIndex; i++) {
arrayToAdd.push(i);
}
// add the values from arrayToAdd in the order of the indexes in the input
$.each(value, function (innerindex, innerindexvalue) {
output.push(arrayToAdd[innerindexvalue]);
});
});
console.log(output);

Categories