Invalid attempt to spread non-iterable instance on an object [duplicate] - javascript

This question already has answers here:
Why are Objects not Iterable in JavaScript?
(7 answers)
Closed 3 years ago.
data: [],
...
I load data from API call into data array. Then I try to arrange the data array into a map which can consist of a key, value pairs (value can be itself array) using below.
const dataMap = {};
for (let i = 0; i < data.length; i+=1) {
const key = data[i].product.name;
const value = data[i];
if (key in dataMap) {
dataMap[key].push(value);
} else {
dataMap[key] = [value];
}
}
But when I do the following I get the following error. What I am doing wrong?
{[...dataMap].map(([key, value]) => {}
Invalid attempt to spread non-iterable instance
This is my dataMap
DataMap is correctly calculate but when i iterate using the following code
Object.entries(dataMap).map((key, value) => {
console.log(key);
console.log(value)
})
it prints out the following. Value is some index which i dont understand why ? Value should be an array. My dataMap is a key, value (value is an array)

Your problem has nothing to do with react/react-native, its plain javascript:
dataMap is already an object, so you only can spread its entries.
// An empty object assign.
const dataMap = {};
// Shallow copy
const objShallowCopy = {...dataMap};
Also, you can rewrite your for-loops using reduce():
const dataSource = [
{ product: { name: 1 }, value: 10 },
{ product: { name: 1 }, value: 100 },
{ product: { name: 2 }, value: 30 },
{ product: { name: 2 }, value: 20 }
];
const dataMap = dataSource.reduce((acc, curr) => {
const prodArr = acc[curr.product.name];
return { ...acc, [curr.product.name]: prodArr ? [...prodArr, curr] : [curr] };
}, {});
console.log(dataMap);
Moreover, Object.entries returns an entries array so you need to fix your loggings:
// Bug
Object.entries(dataMap).map((key, value) => {
console.log(key);
console.log(value);
});
// Good
Object.entries(dataMap).map((([key, value]), index) => {
console.log("key", key);
console.log("value", value);
console.log("index", index);
});

dataMap is object, not an array. You cannot do [...dataMap].
You can convert dataMap to arrays of keys with Object.keys(dataMap) or to array of values with Object.values(dataMap)
So erroneous line should look like
Object.keys(dataMap).map(key => /* dataMap[key] will be value */)

Related

How to update an object value in array of objects when the keys are same

I have an Array of objects and one object
const filterArray = [{bestTimeToVisit: 'Before 10am'}, {bestDayToVisit: Monday}]
This values are setting in a reducer and the payload will be like
{bestTimeToVisit: 'After 10am'}
or
{bestDayToVisit: Tuesday}.
So what I need is when I get a payload {bestTimeToVisit: 'After 10am'} and if bestTimeToVisit not in filterList array, then add this value to the filterList array.
And if bestTimeToVisit already in the array with different value, then replace the value of that object with same key
if(filterArray.hasOwnProperty("bestTimeToVisit")) {
filterArray["bestTimeToVisit"] = payload["bestTimeToVisit"];
} else {
filterArray.push({"bestTimeToVisit": payload["bestTimeToVisit"]});
}
I convert the object array into a regular object and then back into an object array. makes things less complicated. I'm making the assumption each object coming back only has one key/value and that order doesnt matter.
const objectArraytoObject = (arr) =>
arr.reduce((acc, item) => {
const key = [Object.keys(item)[0]];
return { ...acc, [key]: item[key] };
}, {});
const newValues = [{ someKey: 'something' }, { bestDayToVisit: 'Tuesday' }];
const filterArray = [
{ bestTimeToVisit: 'Before 10am' },
{ bestDayToVisit: 'Monday' },
];
const newValuesObj = objectArraytoObject(newValues);
const filterObj = objectArraytoObject(filterArray);
const combined = { ...filterObj, ...newValuesObj };
const combinedToArray = Object.keys(combined).map((key) => ({
[key]: combined[key],
}));
console.log(combinedToArray);
Need to iterate over the array and find objects that satisfy for modification or addition if none are found.
function checkReduced(filterrray,valueToCheck="After 10am"){
let isNotFound =true;
for(let timeItem of filterrray) {
if(timeItem.bestTimeToVisit && timeItem.bestTimeToVisit !== valueToCheck) {
timeItem.bestTimeToVisit=valueToCheck;
isNotFound=false;
break;
}
}
if(isNotFound){filterrray.push({bestTimeToVisit:valueToCheck})}
}
const filterArray = [{bestDayToVisit: "Monday"}];
checkReduced(filterArray,"After 9am");//calling the function
const updateOrAdd = (arr, newItem) => {
// get the new item key
const newItemKey = Object.keys(newItem)[0];
// get the object have the same key
const find = arr.find(item => Object.keys(item).includes(newItemKey));
if(find) { // the find object is a reference type
find[newItemKey] = newItem[newItemKey]; // update the value
} else {
arr.push(newItem); // push new item if there is no object have the same key
}
return arr;
}
// tests
updateOrAdd([{ a: 1 }], { b: 2 }) // => [{ a: 1 }, { b: 2 }]
updateOrAdd([{ a: 1 }], { a: 2 }) // => [{ a: 2 }]

How can I store previous values instead of storing the value in array of objects in react state

I am storing the prev values in an array of objects, for example [{ActFollow: 'BlN'},{ActSendGift: 'BlY'},{ActSubscribe: 'BlY'}] I want to store the key and values in an object like this {ActFollow: 'BlN',ActSendGift: 'BlY', ActSubscribe: 'BlY'}
const [activityTypes, setActivityTypes] = useState<any>([]); // state
.then((response: any) => {
setActivityTypes((oldArray: any) => [
...oldArray,
{[item.channelSettingTypeId]: response.settingValue},
]);
});
How about this, if the nesting is only one level deep
const data = [{ActFollow: 'BlN',ActSendGift: 'BlY', ActSubscribe: 'BlY'}]
console.log([{...data[0],"hey" : "world"}])
const items = [{ActFollow: 'BlN'},{ActSendGift: 'BlY'},{ActSubscribe: 'BlY'}]
let object = {}
items.forEach(item=>{
for (const [key, value] of Object.entries(item)) {
object = {
...object,
[key]: value
}
}
})
console.log(object)
You can use this simple idea in React also. Just hold on the default empty object in state and update the object.
You can reduce the array of objects into an object.
You can do it by spreading (...) the current object into the resultant object, as shown below:
const
arrOfObjs = [{ ActFollow: "BlN" }, { ActSendGift: "BlY" }, { ActSubscribe: "BlY" }],
obj = arrOfObjs.reduce((res, o) => ({ ...res, ...o }), {});
console.log(obj);
You can also do it using Object.assign, as shown below:
const
arrOfObjs = [{ ActFollow: "BlN" }, { ActSendGift: "BlY" }, { ActSubscribe: "BlY" }],
obj = arrOfObjs.reduce((res, o) => Object.assign(res, o), {});
console.log(obj);
Use Spread Operator
const items = [{ActFollow: 'BlN', Anurag: 26},{ActSendGift: 'BlY'},{ActSubscribe: 'BlY'}]
let obj ={}
items.forEach((item) => {
obj = {
...obj,
...item
}
})
console.log(obj)

Filtering an array based off of another objects values [duplicate]

This question already has answers here:
Filter an array of objects by another object of filters
(4 answers)
Closed last year.
I'd like to filter this programs array (I've simplified the objects):
const programs = [
{
format: "In-Person",
schedule: "Full-Time",
},
{
format: "Remote",
schedule: "Full-Time",
},
{
format: "In-Person",
schedule: "Part-Time",
},
{
format: "Remote",
schedule: "Part-Time",
}
]
based on a filter object:
const filters = {format: "Remote", schedule:"Full-Time"}
My attempt:
let filteredPrograms = programs.filter((program) => {
return Object.entries(filters).every(([key, value]) => {
program[key] == value;
});
});
This should analyze each program, and allow is to pass through the filter IF:
For every filter key, the program[filter key] value matches the filter value
But I'm getting an empty array for filteredPrograms
Return the comparison result inside the every callback:
const programs=[{format:"In-Person",schedule:"Full-Time"},{format:"Remote",schedule:"Full-Time"},{format:"In-Person",schedule:"Part-Time"},{format:"Remote",schedule:"Part-Time"}],filters={format:"Remote",schedule:"Full-Time"};
let filteredPrograms = programs.filter((program) => {
return Object.entries(filters).every(([key, value]) => {
return program[key] == value;
});
});
console.log(filteredPrograms)
Or make it an arrow function:
const programs=[{format:"In-Person",schedule:"Full-Time"},{format:"Remote",schedule:"Full-Time"},{format:"In-Person",schedule:"Part-Time"},{format:"Remote",schedule:"Part-Time"}],filters={format:"Remote",schedule:"Full-Time"};
let filteredPrograms = programs.filter((program) => {
return Object.entries(filters).every(([key, value]) => program[key] == value);
});
console.log(filteredPrograms)

Recursively list nested object keys

i have an nested object as such:
options = {
religous: {
kosher: {
value: 'Kosher',
chosen: false
},
halal: {
value: 'Halal',
active: false
},
},
vegan: {
value: 'Vegan',
active: false
}
}
It contains nested objects of varying sizes. I would like to get an Array containing the values of any value propery. So for the above object the desired output would be:
['Kosher', 'Halal', 'Vegan']
Order doesn't really matter.
I tried to do so recursively as such:
getListOfLabels = obj => {
const lst = []
for (let key in obj) {
if (obj[key].value) lst.push(obj[key].value)
else return getListOfLabels(obj[key])
}
return lst
}
but I keep getting a RangeError: Maximum call stack size exceeded error.
Any suggestions?
The for...in loop assigns the key. To get the value use obj[key]. If the key is value add to lst, if it's an object, call getListOfLabels on it, and spread the results into lst.push():
const options = {"religous":{"kosher":{"value":"Kosher","chosen":false},"halal":{"value":"Halal","active":false}},"vegan":{"value":"Vegan","active":false}}
const getListOfLabels = obj => {
const lst = []
for (let key in obj) {
const val = obj[key] // get the value
if (key === 'value') lst.push(val) // if the key name is "value" push to lst
else if(typeof val === 'object') lst.push(...getListOfLabels(val)) // if type of value is object, iterate it with getListOfLabels and push the results into lst
}
return lst
}
const result = getListOfLabels(options)
console.log(result)
You could take a recursive approach and check if the object contains a value key.
function getValues(object, key) {
if (key in object) return [object[key]];
return Object.values(object).reduce((r, v) => {
if (v && typeof v === 'object') r.push(...getValues(v, key));
return r;
}, []);
}
var options = { religous: { kosher: { value: 'Kosher', chosen: false }, halal: { value: 'Halal', active: false } }, vegan: { value: 'Vegan', active: false } };
console.log(getValues(options, 'value'));
Here's a succinct approach using reduce :-D
const getValues = options => Object.values(options)
.reduce((acc, optionObj) => (
optionObj.value ? [ ...acc, optionObj.value ] : [
...acc,
...Object.values(optionObj).reduce((arr, { value }) => ([ ...arr, value ]), [])
]), [])

Array.map function isn't applying to Object value

I'm attempting to re-map an Object that comes from an API call.
The format of the response is the following:
data: {
foo: [{
id: "1",
name: "joe",
info: "whatever"
}, {
id: "2",
name: "anna",
info: "whatever"
},...],
bar: [...]
}
The code I'm using to re-map the object inside each response array is:
const DATA = response.data;
const entries = Object.entries(DATA);
for (const entry of entries) {
entry[1].map(entry => ({
id: entry["id"],
mixed_info: entry["name"] + ", " + entry["info"]
}));
}
When I console.log the data after this, it shows the same as the initial response, as if it completly ignored the map function.
What am I doing wrong? Thanks for the attention.
map returns a new array, you are ignoring the result of the call.
Assign the result of the map call:
entry[1] = entry[1].map(...);
Array.prototype.map returns a new array - it doesn't modify the original.
You have to reassign the entry:
entry[1] = entry[1].map(/*...*/);
However that will only get reflected to the array inside entries, it won't change DATA. To change that, you have to either turn the key value pairs back into an object at the end:
DATA = Object.fromEntries(entries);
Or you have to reassign the DATA properties while iterating:
DATA[ entry[0] ] = entry[1].map(/*...*/);
I'd do:
const { data } = response;
for(const [key, value] of Object.entries(data)) {
data[key] = value.map(/*...*/);
}
let result = {};
for (const entry of entries) {
result[entry[0]] = entry[1].map(entry => ({
id: entry.id,
mixed_info: `${entry["name"] }, ${ entry["info"]}`,
}));
}
'result' contains exact remapped object.

Categories