.map() not a function within reduce() - javascript

I have the following code:
map(res => {
const finalRows = res.reduce((acc, curr) => {
return [
...acc,
...curr.map(row => ({
...row,
chevron: ' ',
}))
]
}, []);
.....
'res' looks like an array of objects, those objects being rows. Using reduce(), it should return an array, but I am using map to go through each of the current rows and adding a 'chevron' column. I feel like maybe it doesn't know it's returning an array yet and treating it like an object still, therefore I'm getting the error 'curr.map not a function', however, I'm not sure if that is the real issue. Any ideas?

Let's take a deeper look at your code:
As you said, res is an array of objects
The second argument of .reduce's callback is the current item in the provided array
So curr is an item of res
But here, it seems that curr isn't an array but instead another type of object (like JSON), which is why you're getting this error.
It would only have worked if res had been an array of arrays, as .map cannot be called on non-array objects.
Also, another way of writing your code in a more simple way is:
// For each row of the `res` array...
res.map(row => {
// Clone it, so the new row isn't linked to the existing one
const newRow = row.slice(0);
// Set its 'chevron' property
newRow.chevron = ' ';
// Return the new row
return newRow;
}); // Here we get the new array of objects

Related

Converting arrays nested in array into object using forEch (does not work somehow?)

I am having trouble with something i thought it will be simple.
I have an array of nested arrays with strings.
const cities = [['Vienna'],['Berlin'],['London'],['Oslo'],['New York']]
I must convert these nested arrays into objects. I think forEach method should suit perfectly along with Object.assign.
I written something like these:
function convert(element) {
Object.assign({}, element)
}
const Test = cities.forEach(convert)
But then i am getting from console.log(Test) undefinded. Why so ? I am iterating through the whole array and each of her arrays should be assign as object. Whats missing ?
Object should contain key: value pair
If you want to convert each string element into an object element. Then you can do something like this :
const cities = [['Vienna'],['Berlin'],['London'],['Oslo'],['New York']]
const res = cities.map((item) => {
return {
city: item[0]
}
});
console.log(res);

how to push the data from a select in a single array?

I'm using react-select, my api expects that i send an array of strings like this ["purple", "red", "orange"] but react-select gives me an array of objects, so what I did was map throught newValue picking each value and putting in an vaiable array, but i'm getting each value in separated arrays like this ["purple"], ["red"], ["orange"]
handleChange = (newValue: any, actionMeta: any) => {
console.log("newValue-->",newValue);
newValue.map((obj: any) => {
const array = [];
array.push(obj.value);
console.log("array-->",array);
});
complete code:
https://codesandbox.io/s/react-codesandboxer-example-sf7tz?file=/example.js
Initialize your array outside before map.
Otherwise you are creating new array for each object.
const array = [];
newValue.map((obj: any) => {
array.push(obj.value);
console.log("array-->",array);
});
As per the react select docs, it should be an array of objects with value and label. so in your case you can do in the below way.
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
let input = ["purple", "red", "orange"]
let output = input.map(item => ({value: item, label: capitalizeFirstLetter(item) }))
console.log(output)
Explanation on the Question snippet
newValue.map((obj: any) => {
const array = [];
array.push(obj.value);
console.log("array-->",array);
});
Here you are mapping through each object, then every time mapping you are creating an empty array, to that array you push the value and print it.
So take first item as example, red iterates -> empty array created -> push the red value to empty array and then printing it.
So this loops three times since the length of the array is 3, so three times you get the array.
Fix on the question snippet is declare the array outside the loop and push in the same manner as the doc suggest then you can pass to react select component as options props and it will work as expected.

Nested array not returning expected value

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);

How to omit a particular key while pushing json objects to an array?

So, I have a JSON array of objects , which in turn contains other arrays of objects. This array of objects has no particular fixed structure as such so its very difficult for me do something like delete mainArray[0].obj.subobj[1].objToOmit;
So I have a key/object called possibleAnswers which I need to remove/omit. In my program I am pushing the contents of one array into another array. So while I am pushing the contents of first array of objects into another, I need to omit the possibleAnswers object from being pushed.
Is there any way or function that searches an array of objects and helps me omit the necessary key? Or what would be a solution as per your thoughts?
Example :
Here is a minimal example: https://codebeautify.org/jsonviewer/cb9fea0d
Edit: In the above JSON there is a key called possibleMembers which is wrong. its possibleAnswers
var collectObservationsFromConceptSets = function () {
$scope.consultation.observations = [];
_.each($scope.consultation.selectedObsTemplates, function (conceptSetSection) {
if (conceptSetSection.observations) {
_.each(conceptSetSection.observations, function (obs) {
$scope.consultation.observations.push(obs);
});
}
});
}
In the above code while pushing the object into another array, how can I omit the possibleAnswers keys? Is there a way to omit?
Thanks a lot people! Both the answers are correct and have generated the exact correct output. Unfortunately I can only select 1 answer as correct and its going to be random.
This is a recursive omit that uses _.transform() to iterate and ignore one or more keys in an array:
const omitRecursive = (keys, obj) => _.transform(obj, (acc, v, k) => {
// if key is view, and it and has an id value replace it with equivalent from views
if(keys.includes(k)) return;
acc[k] = _.isObject(v) ? omitRecursive(keys, v) : v;
});
const data = [{"observations":[{"possibleAnswers":[],"groupMembers":[{"possibleAnswers":[]},{"groupMembers":[{"possibleMembers":[]},{"possibleMembers":[]}]}]}]},{"observations":"Same as above"},{"observations":"Same as above"}];
const result = omitRecursive(['possibleAnswers'], data);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
This function will remove all 'possibleAnswers' if called on your original array like removeKey(arr, 'possibleAnswers')
function removeKey(objOrArr, keyToRemove) {
if (Array.isArray(objOrArr)) {
objOrArr.forEach(o => removeKey(o, keyToRemove));
} else if (typeof objOrArr === 'object') {
delete objOrArr[keyToRemove];
Object.values(objOrArr).forEach(v => removeKey(v, keyToRemove));
}
}

How to avoid "Arrow function expect to return a value" error in Airbnb ESLint

I am running eslint and it is recommended to return a value whenever an arrow function(lambda function) is used. Well that makes sense. However, I come across a case that is hard to walk around.
Dict = {}
Instances = [/* an array of items where items is a dictionary that contains data */]
Instances.map((item) => {
Dict[item.name] = item.url;
});
My goal is to get the data from the Instances array and fill the dictionary Dict with it. I am using the array function to assign key value pair to the dictionary, but that violates the rule of the arrow function.
Is there any iteratools or functions other than map that would help me to achieve the goal, and avoid the rule violation?
Edit: This does not adhere to Airbnb's ES6 Style Guide.
My goal is to get the data from the Instances array and fill the dictionary with it.
Use .reduce
.. and just pass an empty object as the accumulator, filling it up as you iterate through your array.
const instances = [
{ name: 'foo', url: 'https://google.com' },
{ name: 'bar', url: 'https://stackoverflow.com' }
]
const result = instances.reduce((dict, item) => {
dict[item.name] = item.url
return dict
}, {})
console.log(result)
Why not .map?
Array.map always returns a new Array and is meant for mapping each array element to another format.
If your resulting data structure shouldn't be an Array, with the same length as the Array you are operating on, you should avoid using it.
Why .reduce instead of .forEach?
I use forEach only for doing "work" rather than transforming data. Transforming data is almost always achievable with just map and/or reduce.
Here's what I mean by "work":
const users = [userInstance, userInstance, userInstance]
users.forEach(user => user.sendEmail('Hello World'))
Use forEach instead of map.
The point of map is to modify each item in an array and put the modified versions in a new array.
forEach just runs a function on each item.
If you are looking for ES6 solution to fill dictionary object this could help and should pass ESLint also:-
const dict = Instances.reduce((map, obj) => (map[obj.name] = obj.url, map), {});
update
const dict = Instances.reduce((map, obj) => {
let mapClone = {};
mapClone = Object.assign({}, map);
mapClone[obj.name] = obj.url;
return mapClone;
}, {});

Categories

Resources