Related
I have an array of objects
[
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}]
]
That I need to reduce to [{data:3},{data:6},{data:9}] via addition.
Objects of index 0 are added, objects of index 1 are added, and objects of index 2 are added.
Is there a Javascript function like reduce that can manage this?
The previous answer is good but it only works if your arrays are always the same size.
For example, having this initial input would break the code:
[
[{data:1},{data:2},{data:3}, {data:4}],
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}]
]
To fix that you could add a check inside the reducer, to make sure the next array has an object at that index.
Another problem is if you have this initial input:
[
[{data:1},{data:2},{data:3}, {data:4}],
[{data:1},{data:2},{data:3}, {data:4}, {data:5}],
[{data:1},{data:2},{data:3}]
]
The last object in the second array would be ignored because the initial reducer only takes into consideration the length of the first array.
To handle those exceptions, you could use this refactored code (based on #mickl answer):
// Initial input with different format
const initialInput = [
[{data:1},{data:2},{data:3}, {data:4}],
[{data:1},{data:2},{data:3}, {data:4}, {data:5}],
[{data:1},{data:2},{data:3}]
];
// Sort and reverse to get the array with most items first
const sortedInput = initialInput.sort().reverse();
// Finally use the refactored reducer
const result = sortedInput.reduce((arr,cur) => {
return arr.map((val, i) => {
// This "if" checks if the next array has an item on the same index of previous array
// Which is not the case, for example, from the second to the third item
if (cur[i] && cur[i].data) {
return { data: val.data + cur[i].data }
} else {
return { data: val.data}
}
})
});
console.log(result)
You can use array.reduce to aggregate the data across multiple arrays and array.map to sum up the values since it takes an arrow function where second parameter represents an index of currently processed element:
let input = [
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}],
[{data:1},{data:2},{data:3}]
];
let result = input.reduce((arr,cur) =>
arr.map((val, i) => ({ data: val.data + cur[i].data })));
console.log(result);
i have an array of obejcts that has this structure
let events = [ {
"initDate": "2019-11-20",
"finalDate": "2019-11-22",
"intermediateDates": [
"2019-11-20",
"2019-11-21"
],
"priority": 1
},....]
So, i'm trying to get the object that matches from a given array of dates for example :
let filteredDays = [
"2019-11-20",
"2019-11-21",
"2019-11-22"
]
i'm trying with lodash like this:
let eventsFound= [];
let intersection = _.map( this.events,function(value){
let inter = _.intersection(value.intermediateDates,filteredDates);
console.log(inter);
if(inter != []){
foundEvents.push(value);
return value;
}else{
return false;
}
});
when i console log inter i get the first array with values then the next arrays are empty but it keeps pushing all the events into the foundEvents Array and the returned array is the same as the events array.
You're comparing two arrays using !=. In javascript [] != [] is always true. To check if an array is empty, use length property like arr.length == 0.
Use filter instead of using map like a forEach.
To check existance use some/includes combo instead of looking for intersections.
So, filter events that some of its intermediateDates are included in filteredDates:
let eventsFound = _.filter(this.events, event =>
_.some(event.intermediateDates, date =>
_.includes(filteredDates, date)
)
);
The same using native functions:
let eventsFound = this.events.filter(event =>
event.intermediateDates.some(date =>
filteredDates.includes(date)
)
);
I am trying to get access to individual values in an array within an array, I have the overall array, which has arrays in it, and then within that, I want to be able to access those values.
I would also likely assign each of those values to variables.
Essentially I am trying to iterate through what would become a grid of values (an array within an array) using JS.
1) I've tried accessing the value by pushing the row values into the array as a JSON string and then mapping it as array.map => row.map and then mapping it into individual elements
2) I've tried 'destructuring' the object but that did not seem to go anywhere either.
async function dataFormat(worksheet, rowNumber) {
csvWorkbook = workbook.csv.readFile("./uploads/uploadedFile.csv");
await csvWorkbook.then(async function(result) {
let restarts = 0;
let nullCounts = true;
let thermostatRows = [];
// you have to define THEN destructure the array
// const [serial,date,startDate,endDate,thing3,thing4,thing5] = firstTemps
worksheet.eachRow({ includeEmpty: true }, function(row, rowNumber) {
if (rowNumber > 6) {
Rows.push(`${JSON.stringify(row.values)}`);
}
});
console.log(thermostatRows[0])
})
};
Here is my function that returns the first row. If I put Rows[0][0] I get a letter.
here is the return of Rows[1]
[null,"2018-12 03T05:00:00.000Z","16:35:00","heat","heatOff", "hold","Home",70.1,70.1,69.8,43,33.8,0,0,15,15,null,69.8,43,1]
Which makes sense as it is the first row.
but logging Rows[0][0] gives me the first letter of null (first value in the array)
Lastly ,
[ '[null,"2018-12-02T05:00:00.000Z","23:25:00","heat","heatOff","auto","Home",72,72,72,47,41.3,0,0,0,0,null,72,47,0]',
'[null,"2018-12-03T05:00:00.000Z","16:35:00","heat","heatOff","hold","Home",70.1,70.1,69.8,43,33.8,0,0,15,15,null,69.8,43,1]',
'[null,"2018-12 03T05:00:00.000Z","16:40:00",null,null,null,null,null,null,null,null,33.8,0]'
Is the approximate log if I log Rows without anything else - to give you an idea of the whole situation.
edit: my function now looks like this, why would it return undefined?
if (rowNumber > 6) {
thermostatRows.push((row.values));
}
});
thermostatRows.map(thermostatRow => {
// let [date,time,SystemSetting,systemMode,calendarEvent,ProgramMode,coolSetTemp,HeatSetTemp,currentTemp,currentHumidity,outdoorTemp,windSpeed,coolStage1,HeatStage1,Fan,DMOffset,thermostatTemperature,thermostatHumidity,thermostatMotion] = thermostatSettings
console.log(date,time,SystemSetting)
})
})
};```
FINAL UPDATE
It works I figured out the undefined deal myself- try this. (this is with the excel.js library)
async function dataFormat(worksheet, rowNumber) {
csvWorkbook = workbook.csv.readFile("./uploads/uploadedFile.csv");
await csvWorkbook.then(async function(result) {
let restarts = 0;
let nullCounts = true;
let thermostatRows = [];
let thermostatSettings = []; // you have to define THEN destructure the array
// const [serial,date,startDate,endDate,thing3,thing4,thing5] = firstTemps
worksheet.eachRow({ includeEmpty: true }, function(row, rowNumber) {
if (rowNumber > 6) {
thermostatRows.push((row.values));
}
});
thermostatRows.map(thermostatRow => { [,date,time,SystemSetting,systemMode,calendarEvent,ProgramMode,coolSetTemp,HeatSetTemp,currentTemp,currentHumidity,outdoorTemp,windSpeed,coolStage1,HeatStage1,Fan,DMOffset,thermostatTemperature,thermostatHumidity,thermostatMotion] = thermostatRow
console.log(date,time,SystemSetting)
})
})
};
First, you need to be aware that Javascript arrays are zero-indexed. This means that to get the FIRST item, you use index 0. When you're calling Rows[1] you're actually getting the second item.
Second, you aren't creating a 2d array, you're creating a one dimensional array of strings.
Rows.push(`${JSON.stringify(row.values)}`);
This takes row.values and turns it into a string, interpolates it into another string, then pushes the final result into the array.
If you want an array inside the first array, which I assume row.values contains, do Rows.push(row.values);
Why is it that when I want to use the push function inside the reduce function to return a new array I get an error. However, when I use the concat method inside the reduce function, it returns a new array with no problem.
All I'm trying to do is pass an array to the reduce function and return the same array.
var store = [0,1,2,3,4];
var stored = store.reduce(function(pV,cV,cI){
console.log("pv: ", pV);
return pV.push(cV);
},[]);
This returns an error. But when I use concat:
var store = [0,1,2,3,4];
var stored = store.reduce(function(pV,cV,cI){
console.log("pv: ", pV);
return pV.concat(cV);
},[]);
It returns the same array.
Any ideas why?
push returns the new length of the array.
What you need is the initially provided array.
So change the code as below.
var store = [0, 1, 2, 3, 4];
var stored = store.reduce(function(pV, cV, cI){
console.log("pv: ", pV);
pV.push(cV);
return pV; // ********* Important ******
}, []);
concat returns the new array combining the elements of the provided array and concatenated elements. so it works.
Just for completeness, and for the next person who happens on this question, what you're doing is typically achieved with map which, as stated in the docs
map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results
Contrast that with the description of reduce:
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
(Emphasis mine) So you see, although you can manipulate reduce to return a new array, it's general usage is to reduce an array to a single value.
So for your code this would be:
var store = [0,1,2,3,4];
var stored = store.map(function(pV){
console.log("pv: ", pV);
return pV;
});
Much simpler than trying to reconstruct a new array using either push or concat within a reduce function.
I know this is the same answer, but I just want to show that using reduce (), the syntax can also be reduced to a single line of code using ES6:
var store = [0,1,2,3,4];
var stored = store.reduce((pV,cV) => [...pV, cV], []);
console.log(stored);
reduce() can be useful if you need to return an array with multiple items for each item iterated:
var inputs = media.reduce((passedArray, video) => {
passedArray.push("-i");
passedArray.push(video.filepath);
return passedArray;
}, []);
Here it's being used to build the input array for FFmpeg;
[{ name: "bob", filepath: "1.mp4" }, { name: "sue", filepath: "3.mp4" }]
=> ["-i", "1.mp4", "-i", "2.mp4]
Array.prototype.push method returns the new length of the array.
Array.prototype.concat method inserts new element into array and returns array back so it can be further processed. This is what you need to do with reduce: pass modified array the the next iteration.
You can always use destructuring:
var store = [0,1,2,3,4];
var stored = store.reduce(function(pV,cV,cI){
console.log("pv: ", pV);
return [...pV, cV];
},[]);
console.log(stored);
I have two arrays of objects, and I want to filter the first one according to whats on the second one. Here's an example:
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
So in this case what I want to return is an array with the objects that have id's 23 and 54 of the first array, with all its possible properties (in this case, title).
Could you give me any hint that could help me?
Get a list of the indexes you want to search on using map:
var indexes = ary2.map(function (el) {
return el.id;
});
filter the results based on the list of indexes:
var result = ary1.filter(function (el) {
return indexes.indexOf(el.id) > -1;
});
DEMO
This might help you.
Loop through ary2, building up an array of each id value (let's call this array existingIds).
After that loop, now loop through ary1. For each item in ary1, check to see if the id value exists in the existingIds array that we just built up. If it does, append the current item to a result array.
I could write the code for you, but it will be a better learning experience if you first try this yourself :)
Might as well make use of some functional programming built into javascript.
filteredResults = ary1.filter(function(ele){
return (ary2.map(function(idobj){return idobj.id;}).indexOf(ele.id)>-1)
})
filter(function) will iterate through each element of an array, passing it through a callback function. From within that callback iff a true is returned, that value is kept. If false, that value is filtered out.
Also map(function) will iterate through each element of an array passing a callback value as well. All values returned from map callback will be injected into the result. So we can take the id from each element in ary2 and return it in the map function.
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
//Filter for the available ID's, store the resulting objects in a new array
filteredResults = ary1.filter(function(ele){
//map creates an array of just ID's
return (ary2.map(function(idobj){return idobj.id;}).indexOf(ele.id)>-1)
})
//now do whatever you were planning on doing with your results/
var res = document.getElementById("results");
filteredResults.forEach(function(ele){
res.innerHTML+="<li>{id:"+ele.id + ",title:" +ele.title+"}</li>"
})
console.log(filteredResults);
<ul id="results"></ul>
try this:
var ary1 = [{id: 23, title: 'blabla'},{id:43, title: 'bleble'}, {id:54, title:'blibli'}];
var ary2 = [{id:23},{id:54}, {id:65}];
var newary=[];
for(x in ary1){
for(y in ary2){
if(ary1[x].id == ary2[y].id){
newary.push(ary1[x]);
}
}
}
console.log(newary);// here newary will be your return newary;