adding indexed values of arrays created in a forEach() - javascript

I am trying to add the values of multiple arrays (one starts out empty, but all the ones I am adding to it are the same length, though it be great if we could come up with something that adds them even if they are all different lengths) - not the sum of all values in each array, instead, sum of the values in the same index. For example:
array1 = [1, 2, 3]
array2 = [2, 3, 4]
desiredArray = [3, 5, 7]
The number of the arrays I will be adding is arbitrary, as they are created based on the users selection. (Based on the length of the array created from the selection). I want to sum the arrays by index to create a new array, and from the new array, I will create a decline curve. When I attempt to add them using "indexSum" I get an array below back full of NaaNs...though they are the correct legth:
requestedOil
requestedGas
requestedWater
These are the temporary arrays created by the length of the var "values" - these are the ones I am trying to add by respective index to eventually get the ones mentioned above:
Oil[well]
Gas[well]
Water[well]
THIS IS THE FUNCTON I CURRENTLY HAVE TO ADD ARRAYS AND CALLED WHEN USER MAKES SELECTION FROM multiple-site-selection
function updateCurves(){
var dropdownMenu = document.getElementById("multiple-site-selection").selectedOptions;
var values = Array.from(dropdownMenu).map(({ value }) => value);
console.log(values);
d3.json('./static/wellNames.json').then((data) => { //read in the wellNames.json file, which contains the array "names" with all the well names
wellOptions = data.names;
forSelection = wellOptions.map((x) => ({id:x}))
console.log(forSelection);
d3.json("./static/all_production.json").then((data) =>{
var requestedOil = [];
var requestedGas = [];
var requestedWater = [];
var site_date = [];
var Oil = [];
var Gas = [];
var Water = [];
values.forEach((well) => {
forSelection.forEach((pair) => {
if(well == Object.values(pair)){
Oil[well] = new Array();
Gas[well] = new Array();
Water[well] = new Array();
new Promise ((resolve) => data.forEach((site) => {
if(values.length == 1 && well == site[0]){
requestedOil.push(site[2]);
requestedGas.push(site[3]);
requestedWater.push(site[4]);
site_date.push(site[8])}
else if(values.length > 1 && well == site[0]){
indexSum = (a1, a2) => a1.map((v, i) => i + a2[v]);
Oil[well].push(site[2])
requestedOil = indexSum(Oil[well], requestedOil);
Gas[well].push(site[3])
requestedGas = indexSum(Gas[well], requestedGas);
Water[well].push(site[4])
requestedWater = indexSum(Water[well], requestedWater);
site_date.push(site[8])}
else{}
resolve()}))//PROMISE CLOSED
} //IF CLOSED
})//forSelection (dic containing names of well selected) closed
console.log(Oil[well]);
}); //values.forEach closed
THIS CODE CURRENTLY WORKS AS I AM NOT ADDING ANY ARRAYS AND IT IS CALLED AS SOON AS THE WEBPAGE LOADS
//FUNCTION TO CREATE DROP DOWN VALUES
function createDropdownOptions() {
var selector = d3.select("#multiple-site-selection"); //select dropdown <select> in well.html with id:"siteSelection"
d3.json('./static/wellNames.json').then((data) => { //read in the wellNames.json file, which contains the array "names" with all the well names
var wellOptions = data.names;
wellOptions.forEach((well) => {
selector
.append('option')
.text(well)
.property('Value', well);
})
})
};
createDropdownOptions(); //CALL FUNCTION TO CREATE DROPDOWN MENU VALUES
// //FUNCTION TO CREATE HOME/SUMMARY CURVES
function curvesHome() {
d3.json("./static/all_production.json").then((data) =>{ //THIS WORKS!!!
var site_oil = [];
var site_gas = [];
var site_water = [];
summarySiteDate = [];
new Promise ((resolve) => data.forEach(site => {if (site[0]==="Summary") {
site_oil.push(site[2]);
site_gas.push(site[3]);
site_water.push(site[4]);
summarySiteDate.push(site[8]);
} resolve()}));
//CALL FUNCTION TO CREATE DROPDOWN MENU VALUES
var mostRecentEntry = summarySiteDate[0]; //MOST RECENT DATE WITHOUT HOUR AS VARIABLE
var addingHours = "T00:00"; //HOURS TO ADD TO MOST RECENT DATE - NEEDED TO NORMALIZE FROM ORIGINAL 19 HOUR FORMAT
var nextYear = mostRecentEntry.concat(addingHours); //DATE AND HOUR AS SINGLE VARIABLE TO MAKE INTO DATE
var mostRecentDate = new Date(nextYear); //MAKE VARIABLE INTO DATE
var nextYearsDate = new Date(mostRecentDate.setFullYear(mostRecentDate.getFullYear() + 1)); //GET YEAR FROM MOST RECENT DATE AND ADD A YEAR
var nextYear= nextYearsDate.getFullYear() //GET NEXT YEARS DATE
var nextMonth= nextYearsDate.getMonth() + 1 // GET NEXTS YEARS MONTH, ADD ONE BECAUSE MONTHS ARE INDEXED AT 0
var nextDate= nextYearsDate.getDate() //GET NEXT YEARS DATE
nextYearGraph = `${nextYear}-${nextMonth}-${nextDate}`; // CREATE FULL DATE FOR NEXT YEAR IN RIGHT FORMAT FOR AXIS
console.log(`${nextYearGraph} is a year from the most recent production date. This is from curvesHome()`);
var dataOil = [{
x: summarySiteDate,
y: site_oil,
type: "line",
line:
{color: "green"}
}];
var layoutOil = {
title: "Oil BBL",
yaxis: {
type: 'log',
autorange: true
},
xaxis: {
autorange: false,
range: [summarySiteDate[summarySiteDate.length-1], nextYearGraph]
}
};
Plotly.newPlot("oilDeclineCurve", dataOil, layoutOil);
// gas decline curve data
var dataGas = [{
x: summarySiteDate,
y: site_gas,
type: "line",
line: {color: "red"}
}];
var layoutGas = {
title: "Gas BBL",
yaxis: {
type: 'log',
autorange: true
},
xaxis: {
autorange: false,
range: [summarySiteDate[summarySiteDate.length-1], nextYearGraph]
}
};
Plotly.newPlot("gasDeclineCurve", dataGas, layoutGas);
// water decline curve data
var dataWater = [{
x: summarySiteDate,
y: site_water,
type: "line" }
];
var layoutWater = {
title: "Water BBL",
yaxis: {
type: 'log',
autorange: true
},
xaxis: {
autorange: false,
range: [summarySiteDate[summarySiteDate.length-1], nextYearGraph]
}
};
Plotly.newPlot("waterDeclineCurve", dataWater, layoutWater);
})};
I have both HTML sand JS in my code, so it is probably best if you have the whole thing to better understand what I am doing and trying to do. Here are my links:
My repo:
My GitPage
Thank you in advanced!

Here is a function that bases length off of first array length and doesn't care about the number of input arrays
function stackSum(arr) {
return arr[0].map((a, i) => {
let r = 0;
arr.forEach(b, j) => r+=arr[j][i]);
return r;
})
}
console.log(stackSum([
[1,1,1],
[1,2,2],
[2,2,3],
[3,7,7]
]).join(','));
console.log(stackSum([
[1,2,3],
[2,3,4]
]).join(','));

Since the arrays are of equal lengths, you can simply use Array#map.
const
indexSum = (a1, a2) => a1.map((v, i) => v + a2[i]),
desiredArray = indexSum([1, 2, 3], [4, 5, 6])
console.log(desiredArray)

Related

combine object arrays recursively javascript/ typescript

I have n number of arrays structured like
[{val_1: 2}, {val_1: 3}];
[{val_2: 2}];
[{val_3: 1}];
etc.
I want to create a single array structured like
[{val_1: 2, val_2: 2, val_3: 1}, {val_1: 3, val_2: 2, val_3: 1}]
in which all arrays are compared and every single possible output is produced. In the below code I have 3 arrays. One with 4 values, 2 values, and 3 values. I want it to return 24 different arrays showing all possible combinations.
var val_1 = 3
var val_2 = 2
var val_3 = 1
var total_val = 3;
var useable = 50;
var array_1 = new Array();
var array_2 = new Array();
var array_3 = new Array();
var array_1_c = new Array();
var array_2_c = new Array();
var array_3_c = new Array();
for(val_1; val_1 <= total_val && val_1 <= useable; val_1+=1){
array_1 = [{val_1}];
array_1.map(test =>{
return{val_1}
}).forEach(test => array_1_c.push(test));
};
var val_1 = 2
for(val_1; val_1 >= 0; val_1-=1){
array_1 = [{val_1}];
array_1.map(test =>{
return{val_1}
}).forEach(test => array_1_c.push(test));
};
for(val_2; val_2 <= total_val && val_2 <= useable; val_2+=1){
array_2 = [{val_2}];
array_2.map(test =>{
return{val_2}
}).forEach(test => array_2_c.push(test));
};
for(val_3; val_3 <= total_val && val_3 <= useable; val_3+=1){
array_3 = [{val_3}];
array_3.map(test =>{
return{val_3}
}).forEach(test => array_3_c.push(test));
}; console.log(array_1_c);console.log(array_2_c);console.log(array_3_c);
how would something like this be accomplished? The permute function seems to be the way to go, but I can't find a way to output every single combination. If creating multiple million combinations should I go a different route than using an object array.
Thanks!
You could take an algorithm for a cartesian product by using arrays of objects.
The result is an array of object with all properties of the given data.
const
getCartesian = array => array.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => ({ ...v, ...w }))), [])),
all = [[{ val_1: 2 }, { val_1: 3 }], [{ val_2: 2 }], [{ val_3: 1 }]],
cartesian = getCartesian(all);
console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }

JavaScript - Arbitrary Sort [duplicate]

This question already has answers here:
Javascript - sort array based on another array
(26 answers)
Closed 3 years ago.
I have an array like this:
var data = ['High', 'Low', 'Medium'];
This data array is created dynamically. So, it may have all 3 values or only 2 values or 1 value.
Regardless of the values in the array, I would like the array to be sorted in this fashion:
var sortedArray = ['High', 'Medium', 'Low']
I have tried something like this:
var sortedArray = []
for(var 0;i<data.length;i++)
{
if(data[i] = 'High')
{
sortedArray.push('High');
}
else if(data[i] = 'Medium')
{
sortedArray.push('Medium');
}
else if(data[i] = 'Low')
{
sortedArray.push('Low');
}
}
How can we achieve that?
You can start with the complete array already sorted, and filter out the elements that aren't in data.
var data = ['Low', 'High'];
var sortedArray = ['High', 'Medium', 'Low'].filter( el => data.includes( el ) );
console.log( sortedArray );
var data = ['High', 'Low', 'Medium'];
// create a dictionary to map each possible value
var map = {High: 3, Medium: 2, Low: 1, Default:0 };
// then sort
var sorted = data.sort((a,b)=>(map[a]||map.Default)>(map[b]||map.Default)?-1:1);
console.log(sorted);

How to check in array how much times each word repeats itself and push it to another array [duplicate]

This question already has answers here:
Counting the occurrences / frequency of array elements
(39 answers)
Closed 5 years ago.
Lets say i have an array like this:
let votesArr = [yes,no,yes,no,yes];
and i want to to count how much times every word repeats itself and push to another so the output looks like this:
let votesData = [3,2]; // 3 for three yeses and 2 for two nos.
and i want to to work on many types of arrays like this, lets say an array that has 3 or 4 unique word.
I'm trying for a lot of time already and can't do that.
You could use the power of Map.
var array = ['yes', 'no', 'yes', 'no', 'yes'],
map = new Map,
result;
array.forEach(v => map.set(v, (map.get(v) || 0) + 1));
result = [...map.values()];
console.log(result);
Just returning a plain array of counts will not make sense I guess. It should be more like below. If you don't want this output then just map the values to form an array.
{
"yes": 3,
"no": 2
}
let votesArr = ["yes","no","yes","no","yes"];
const mappedArr = votesArr.reduce((a, b) => {
a[b] = a[b] || 0;
a[b] += 1;
return a;
}, {});
console.log(mappedArr);
You can do this as follows:
let votesArr = ["yes","no","yes","no","yes"];
let countSummary = votesArr.reduce( (count, val) => {
if(!count[val]) { count[val] = 0 }
count[val]++;
return count;
}, {})
console.log(countSummary)// {yes: 3, no: 2}
let countSummmaryArr = Object.keys(countSummary).map(k=>countSummary[k]);
console.log(countSummmaryArr )// [3,2]
The way this works is that the .reduce counts every instance to a map of values, and the .map converts it to an array of the values.
The below does what you need, although I'm sure it could be cleaned up a bit.
var data = ["Unsure", "Yes", "Yes", "No", "Yes", "No", "Maybe", "Unsure"];
var counts = {};
for (var i = 0; i < data.length; i++) {
(counts[data[i]]) ? counts[data[i]]++ : counts[data[i]] = 1;
}
// counts = {Unsure: 2, Yes: 3, No: 2, Maybe: 1}
You can do like this
let votesArr = ['yes', 'no', 'yes', 'no', 'yes'];
// Create an empty object to store array item as key & its
// number of repeat as value
var itemObj = {};
// loop over it and store the value in the object
var m = votesArr.forEach(function(item) {
if (!itemObj[item]) {
itemObj[item] = 1
} else {
itemObj[item] = itemObj[item] + 1
}
});
// Use object.values to retrive the value
console.log(Object.values(itemObj))

Counting array elements with specific date in javascript

I have an array of Date() objects in javascript and I want to count the number of events on each day.
Here is an example:
What I have is:
Array [ Date 2014-12-04T10:30:20.000Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z, Date 2014-12-05T11:04:58.056Z ]
What I want is:
Array [{date: '2014-12-04', counts: 1}, {date: '2014-12-05', counts: 3}]
Thanks a lot!
Max
Basic answer:
var arr = [], // fill it with array with your data
results = {}, rarr = [], i, date;
for (i=0; i<arr.length; i++) {
// get the date
date = [arr[i].getFullYear(),arr[i].getMonth(),arr[i].getDate()].join("-");
results[date] = results[date] || 0;
results[date]++;
}
// you can always convert it into an array of objects, if you must
for (i in results) {
if (results.hasOwnProperty(i)) {
rarr.push({date:i,counts:results[i]});
}
}
These can be made much easier with lodash functions, and Array.forEach() in ES5
You much better off having a simple object with the keys as the date and the value as the count. I've added a simple pad function that prefixes a zero where the number is a single digit as per your output requirements.
function pad(n) {
return n.toString().length == 1 ? '0' + n : n;
}
function getCount(arr) {
var obj = {};
for (var i = 0, l = arr.length; i < l; i++) {
var thisDate = arr[i];
var day = pad(thisDate.getDate());
var month = pad(thisDate.getMonth() + 1);
var year = thisDate.getFullYear();
var key = [year, day, month].join('-');
obj[key] = obj[key] || 0;
obj[key]++;
}
return obj;
}
getCount(arr); // Object { 2014-04-12: 1, 2014-05-12: 3 }
DEMO
I came across the same issue and found this solution which uses Map()
`
calc = (obj) => {
const orders = []
const dates_map = new Map()
//iterate through all the objects inside the orders array
orders.forEach(order => {
// format and get the date
const date = new Date(order.created_at).toLocaleDateString('en-GB')
//check if the date key exists in the Map() and save it in a temp
const temp = dates_map.get(date) || false
// if it does not exist
if (temp) {
// clone the object
const previous = {...temp}
// increase counter
previous.count += 1
dates_map.set(date, previous)
}else{
//create new object to avoid overwriting
const result = {}
result.count = 1
dates_map.set(date, result)
}
})
console.log(dates_map)
}
And this is the output
Output: Map(3) {
'08/05/2021' => { count: 2 },
'09/05/2021' => { count: 1 },
'11/05/2021' => { count: 2,}
}
`

Iterating through object to add up all matching properties

I have a caml query which is going to return something like this in xml.
ID Title Percentage
7;#7 2 1.00000000000000
7;#7 3 0.220000000000000
7;#7 sub 1.1 0
7;#7 4 0.140000000000000
12;#12 7 0.670000000000000
13;#13 6 0.700000000000000
I'll likely create an aray of objects for each item. Something like this:
var result = [{id:7,title:"2",percent:1.0},...,{id:13,title:"6",percent:0.7}]
How could I iterate through the result and add up all the percentages with the same ID so I end up with something like:
var total = [{id:7,percent:1.36,count:4},{id:12,percent:0.67,count:1},{id:13,percent:0.7,count:1}]
Or even if I could just get
percent/count = totalPercentage so I end up with an object with just {id:7,totalPercentage:0.325}
Try this:
var percentages = {};
result.forEach(function (it) {
var obj = percentages[it.id] = percentages[it.id] || {
percent: 0,
count: 0,
id: it.id
};
obj.percent += Number(it.percent); // Casting to Number, in case percent comes as string
obj.count++;
});
This creates an object, with ids as keys. Should you wish to convert it to an array:
total = Object.keys(percentages).map(function (it) {
return percentages[it]
});
To get the average of the percentages, you can do this:
total = total.map(function(it) {
return {
id: it.id,
percent: it.percent / it.count
};
});
Just make the new object and iterate though the old one. You can see a demo here: http://jsfiddle.net/TSyE5/2/
var totalPercent = [],
total = {},
result = [{id:8,title:"3",percent:1.0},{id:7,title:"2",percent:1.0},{id:7,title:"2",percent:3.0},{id:13,title:"6",percent:0.7},{id:13,title:"6",percent:0.7},{id:13,title:"6",percent:0.7}];
$.each(result, function(){
!(this.id in total) && (total[this.id] = {id:this.id, title:this.title, percent:0, count:0});
total[this.id].percent += this.percent;
total[this.id].count++;
});
$.each(total, function(i){
total[i].percent = total[i].percent/total[i].count;
totalPercent.push({id:total[i].id, percent:total[i].percent});
});

Categories