I have an array of objects that I want to iterate over and create a new array of objects.
First I map over the data, then I loop through each object to extract the values. I want to store the Location name and value from each object.
My code is returning null results. I can't change the way data is declared. Can someone help me understand why I keep getting null results?
[
{
"euValue": null,
"asValue": null
}
]
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
let formattedData = [];
let euValue, asValue;
formattedData = data.map(location => {
for (const l in location) {
if (location.hasOwnProperty(l)) {
const _this = location[l];
euValue = _this.Location === "Europe" ? _this.Value : null;
asValue = _this.Location === "Asia" ? _this.Value : null;
}
}
return {
euValue,
asValue
};
});
return formattedData;
};
const newData = formatData();
console.log(newData);
Edit
Expected result is
[
{
"euValue": “Ireland”,
"asValue": “China”
}
]
Assuming that inside data you could have multiple objects with a Location array that have only 2 objects (one for Europe and another one for Asia) you should change your function to something like this
const data = [
{
Locations: [
{
Location: { Name: "Europe" },
Value: "Ireland"
},
{
Location: { Name: "Asia" },
Value: "China"
}
]
}
];
const formatData = () => {
// iterate all data objects
return data.map((topLocation) => {
const res = {};
// loop over Location children objects
topLocation.Locations.forEach((location) => {
const { Name } = location.Location;
// decide where to save Value base on the Location.name
if (Name === "Europe") {
res.euValue = location.Value;
} else if (Name === "Asia") {
res.asValue = location.Value;
}
});
return res;
});
};
const newData = formatData();
console.log(newData);
you missing a second loop also you overwriting the usValue and euValue and you better use forEach instead of map in this case.
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = (data) => {
let formattedData = [],
values = {};
data.forEach(location => {
for (const l in location) {
if (location.hasOwnProperty(l)) {
const _this = location[l];
_this.forEach(el => {
if (el.Location.Name === "Europe") {
values["euValue"] = el.Value || null
}
if (el.Location.Name === "Asia") {
values["asValue"] = el.Value || null
}
})
}
}
});
formattedData.push(values)
return formattedData;
};
console.log(formatData(data))
I don't know what do you want to get from your code but this code may help you.
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
let formattedData = [];
formattedData = data.map(location => {
let euValue = [],
asValue = [];
for (const l in location.Locations) {
if (location.Locations.hasOwnProperty(l)) {
const _this = location.Locations[l];
if (_this.Location.Name === "Europe")
euValue.push(_this.Value);
else if (_this.Location.Name === "Asia")
asValue.push(_this.Value);
}
}
return {
euValue,
asValue
};
});
return formattedData;
};
const newData = formatData();
console.log(newData);
I'm sure many of the other answers are fine but the way I did it was to do the classic for loop to iterate over the data. I would have liked to have kept your ternary operators but I think you may need the if/else syntax.
var data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
let formattedData = [];
let euValue, asValue;
formattedData = data.map(location => {
for (const l in location) {
if (location.hasOwnProperty(l)) {
const _this = location[l];
for (let i = 0; i < _this.length; i++) {
if (_this[i].Location.Name === "Europe") {
euValue = _this[i].Value;
} else if (_this[i].Location.Name === "Asia") {
asValue = _this[i].Value;
} else {
euValue, asValue = null;
}
}
}
}
return {
euValue,
asValue
};
});
return formattedData;
};
const newData = formatData();
console.log(newData);
Using Array.prototype.flatMap() might help you get the array you desire in a cleaner way:
const data = [{
Locations: [{
Location: {
Name: "Europe"
},
Value: "Ireland"
},
{
Location: {
Name: "Asia"
},
Value: "China"
}
]
}];
const formatData = () => {
const formattedData = data.flatMap(item => {
const object = {}
item.Locations.map(location => {
const continent = location.Location.Name
let country = {}
if (continent === 'Europe') country = {
euValue: location.Value
}
if (continent === 'Asia') country = {
asValue: location.Value
}
Object.assign(object, country)
});
return object
});
return formattedData;
}
const newData = formatData();
console.log(newData);
Related
I have data in the following format
const data =
{
"sent_total":429,
"sent_distribution":[
{
"date_triggered__date":"2022-12-07",
"count":92
},
{
"date_triggered__date":"2022-12-08",
"count":337
}
],
"delivered":428,
"delivered_distribution":[
{
"timestamp__date":"2022-12-07",
"count":91
},
{
"timestamp__date":"2022-12-08",
"count":337
}
],
}
Need help in converting this in the following format which separates the data by the key (which is sent or delivered) to an array of objects.
const data = [
{
key: sent,
value: 429,
distribution: [
{
date_triggered__date: "2022-12-07",
count: 92,
},
{
date_triggered__date: "2022-12-08",
count: 337,
},
],
},
];
Hope it helps:
const data =
{
"sent_total":429,
"sent_distribution":[
{
"date_triggered__date":"2022-12-07",
"count":92
},
{
"date_triggered__date":"2022-12-08",
"count":337
}
],
"delivered":428,
"delivered_distribution":[
{
"timestamp__date":"2022-12-07",
"count":91
},
{
"timestamp__date":"2022-12-08",
"count":337
}
],
}
const result = [];
Object.keys(data).map((key) => {
const newKey = key.split("_")[0];
let index = result.findIndex((resultItem) => resultItem.key === newKey);
const value = key.includes("_distribution") ? null : data[key];
const distribution = key.includes("_distribution") ? data[key] : null;
if(index === -1) {
result.push({
key: newKey,
value: value,
distribution: distribution
});
} else {
if(value)
result[index].value = value;
if(distribution)
result[index].distribution = distribution;
}
});
console.log(result);
I have an array
const dataCheck = ["Rohit","Ravi"];
I have another array of object
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
I want to check if any value in dataCheck is present in the userData and then return a new array with the below data
const newData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit", status: "present" },
{ name: "Ravi", status: "present" },
];
I tried to do something using loops but not getting the expected results
const dataCheck = ["Rohit", "Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" }
];
let newDataValue = {};
let newData = [];
userData.forEach((user) => {
const name = user.name;
dataCheck.forEach((userName) => {
if (name === userName) {
newDataValue = {
name: name,
status: "present"
};
} else {
newDataValue = {
name: name
};
}
newData.push(newDataValue);
});
});
console.log(newData);
My trial gives me repeated results multiple results which is just duplicates
You should use map() and a Set.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const set = new Set(dataCheck);
const output = userData.map(data => set.has(data.name) ? ({...data, status: "present"}): data)
console.log(output)
.as-console-wrapper { max-height: 100% !important; top: 0; }
A Set allows for lookups in O(1) time and therefore this algorithm works in O(n) time. If you would use the array for lookups (e.g. using indcludes(), find() etc.) the runtime would be O(n²). Although this will certainly not matter at all for such small arrays, it will become more relevant the larger the array gets.
map() is used here because you want a 1:1 mapping of inputs to outputs. The only thing to determine then is, what the output should be. It is either the input, if the value is not in the Set, or it is the input extended by one property status set to "present". You can check for the presence in a Set using the has() method and can use the ternary operator ? to make the decision which case it is.
const dataCheck = ["Rohit", "Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
// map through every object and check if name property
// exists in data check with help of filter.
// if it exists the length of filter should be 1 so
// you should return { name: el.name, status: "present" } else
// return { name: el.name }
let newData = userData.map((el) => {
if (dataCheck.filter((name) => name === el.name).length > 0) {
return { name: el.name, status: "present" };
} else {
return { name: el.name };
}
});
console.log("newdata: ", newData);
A better approach would be to use map over userData array, find for matching element in dataCheck, if found return matching element + a status key or just return the found element as it is.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const getUpdatedObject = () => {
return userData.map(userData => {
const userDetail = dataCheck.find(data => userData.name === data);
if(userDetail) return {userDetail, status:"present"}
else return {...userData}
});
}
console.log(getUpdatedObject())
Working fiddle
Loop through userData, check if name is includes in dataCheck. If true add status 'present'.
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
for (let user of userData) {
if(dataCheck.includes(user.name)) {
user.status = 'present'
}
}
console.log(userData)
You are seeing repeated results due to the second loop dataCheck.forEach((userName) => { as every loop of dataCheck will fire the if/else statement and add something to the final array. However many values you add to dataCheck will be however many duplicates you get.
Only need to loop through one array and check if the value is in the other array so no duplicates get added.
const dataCheck = ["Rohit", "Ravi"];
const userData = [{ name: "Sagar" }, { name: "Vishal" }, { name: "Rohit" }, { name: "Ravi" }];
let newDataValue = {};
let newData = [];
// loop thru the users
userData.forEach((user) => {
// set the user
const name = user.name;
// check if in array
if (dataCheck.indexOf(name) >= 0) {
newDataValue = {
name: name,
status: "present",
};
}
// not in array
else {
newDataValue = {
name: name,
};
}
newData.push(newDataValue);
});
console.log(newData);
So you will do like this :
const dataCheck = ["Rohit","Ravi"];
const userData = [
{ name: "Sagar" },
{ name: "Vishal" },
{ name: "Rohit" },
{ name: "Ravi" },
];
const newUserData = userData.map( user => {
dataCheck.forEach( data => {
if( data === user.name )
user.status = "present";
});
return user;
} );
console.log( newUserData );
I was trying to update the town name in the below-given JSON structure.
"City":[
{
"Name":"Delhi",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd",
"Towns":[
{
"Name":"MG Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
},
{
"Name":"DLF Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
}
]
},
{
"Name":"Pune",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax",
"Towns":[
{
"Name":"Hadapsar",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1x4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"
},
{
"Name":"Magarpatta",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1f4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bax"
}
]
}
]
I wanted to change the town name from "Hapdasar" to "Viman Nagar" if my cid matches that of Hadapsar Town
Output which I wanted was:
"City":[
{
"Name":"Delhi",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd",
"Towns":[
{
"Name":"MG Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
},
{
"Name":"DLF Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
}
]
},
{
"Name":"Pune",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax",
"Towns":[
{
"Name":"Viman Nagar",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1x4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"
},
{
"Name":"Magarpatta",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1f4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bax"
}
]
}
]
I was using js map to iterate but was confused about how to replicate the exact structure.
Well, map alone is not enough to solve your problem, since you have two nested arrays. Maybe you can consider the possibility to use maptwice?
For example:
var cid = "c5d58bef-f1c2-4b7c-a6d7-f64df12321ax";
var newName = "Viman Nagar";
City = City.map(function(city) {
city.towns = city.towns.map(function(town) {
if (town.cid === cid)
town.name = newName;
return town;
});
return city;
});
Atribute your object for
let cities = [{
"Name": "Delhi"
...
}]
and then you can map over it
let result = cities.map(city => city.Towns.map(town => {
if (town.Name === "Hadapsar") {
return {
...town,
Name: "Viman Nagar"
}
} else return town
}))
Use Array#map as follows:
Iterate over cities
In every iteration, iterate over Towns. If current town's cid is equal to the one to change, update its Name
const changeTownName = (cities = [], cid, name) =>
cities.map(({ Towns = [], ...props }) => ({
...props,
Towns: Towns.map(town => town.cid === cid
? { ...town, Name: name }
: { ...town }
)
}));
const cities = [
{ Name: 'Delhi', id: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bd', Towns: [ { Name: "MG Colony", conditionId: '60d1f5eb-0222-4a84-879b-6699b0cfc1a4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bd' }, { Name: "DLF Colony", conditionId: '60d1f5eb-0222-4a84-879b-7749b0cfc1a4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bd' } ] },
{ Name: 'Pune', id: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321ax', Towns: [ { Name: "Hadapsar", conditionId: '60d1f5eb-0222-4a84-879b-6699b0cfc1x4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321ax' }, { Name: "Magarpatta", conditionId: '60d1f5eb-0222-4a84-879b-7749b0cfc1f4', cid: 'c5d58bef-f1c2-4b7c-a6d7-f64df12321bax' } ] }
];
console.log( changeTownName(cities, 'c5d58bef-f1c2-4b7c-a6d7-f64df12321ax', 'Viman Nagar') );
If you consider city as cities this code can help you;
cities.forEach(city => {
city.Towns = city.Towns.map(el => {
if (el.Name === 'Hapdasar') {
el.Name = 'Viman Nagar';
}
return el;
})
});
You'll need to loop for each city in your array, and each town in the city. If the cid matches the town's cid, then change it;
const myNewTownName = "Viman Nagar";
const cid = "c5d58bef-f1c2-4b7c-a6d7-f64df12321ax";
for(let i = 0; i < myObj.City.length; i++){
const city = myObj.City[i];
for(let j = 0; j < city.Towns.length; j++){
const town = city.Towns[j];
if(cid === town.cid){
town.Name = myNewTownName;
}
city.town[j] = town;//Updates city with the updated town
}
myObj.City[i] = city; //Updates myObj with the updated city
}
The result can also be obtained using nested .forEach loops to parsing through the outer and inner arrays, with an if block to examine the cid for the target town.
const data = {
"City":[
{
"Name":"Delhi",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd",
"Towns":[
{
"Name":"MG Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
},
{
"Name":"DLF Colony",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1a4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bd"
}
]
},
{
"Name":"Pune",
"id":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax",
"Towns":[
{
"Name":"Hadapsar",
"conditionId":"60d1f5eb-0222-4a84-879b-6699b0cfc1x4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"
},
{
"Name":"Magarpatta",
"conditionId":"60d1f5eb-0222-4a84-879b-7749b0cfc1f4",
"cid":"c5d58bef-f1c2-4b7c-a6d7-f64df12321bax"
}
]
}
]
} // end data;
const targetCid = "c5d58bef-f1c2-4b7c-a6d7-f64df12321ax"; // cid for Hadapsar;
const objArray = data.City;
objArray.forEach(element => {
element.Towns.forEach(element => {
if (element.cid == targetCid) {
element.Name = "Viman Nagar";
} // end if;
}); // next object in Towns array;
}); // next object in objArray;
document.getElementById('output').textContent = JSON.stringify(data, undefined, 2);
#output {
white-space: pre;
}
<pre id="output"></pre>
I want to get my file directories as nested array object but i can't seem to figure out how to convert
[
'routes/files',
'routes/files/emptyfolder',
'routes/files/somefolder',
'routes/files/somefolder/example.docx',
'routes/files/test.docx',
'routes/randomdata.json'
]
to
[
{
title: 'routes',
content: [
{
title: 'files',
content: [
{
title: 'empty folder',
content: []
},
{
title: 'somefolder',
content: [
{
title: 'example.docx',
},
]
},
{
title: 'test.docx',
}
],
},
{
title: 'randomdata.json'
}
],
}
]
it looks impossible problem for me to solve.
I would love to know how to solve it.
Thank you.
Here is how I solved it:
Not the best solution, but works.
const arr = [
"routes/files",
"routes/files/emptyfolder",
"routes/files/somefolder",
"routes/files/somefolder/example.docx",
"routes/files/test.docx",
"routes/randomdata.json",
];
const arr2 = arr.map((p) => p.split("/"));
const setNestedObjectField = (
obj,
props,
value
) => {
if (!Array.isArray(obj)) {
if (!obj.content) {
obj.content = [];
}
obj = obj.content;
}
for (const propName of props) {
const next = obj.find((el) => el.title === propName);
if (!next) {
console.assert(props.at(-1) === propName);
// last propName
obj.push(value);
} else {
if (!next.content) {
next.content = [];
}
obj = next.content;
}
}
};
const rez = [];
let index = 0;
while (arr2.some((s) => s[index] !== undefined)) {
// arr2 = arr2.filter((a) => a.length);
const layer = arr2.reduce((acc, pathArr) => {
if (pathArr[index] === undefined) return acc;
acc.add(pathArr.slice(0, index + 1).join("/"));
return acc;
}, new Set());
// console.log({ layer });
for (const key of layer) {
setNestedObjectField(rez, key.split("/"), { title: key.split("/").at(-1) });
}
index++;
}
console.log(rez);
I came across this question and it's an interesting problem, I know it's already been answered, but I wanted to spend a little of my time to solve it my way.
here I leave my code:
function nestedDirectories (arr) {
const splittedArray = arr.map(a => a.split('/'));
return {
mergeObjs: function(target, source) {
for (let key in source) {
if(!target[key]) target[key] = {};
target[key] = this.mergeObjs(target[key], source[key]);
}
return target;
},
buildResponse: function (objMain) {
let arr = [];
for (let key in objMain) {
let o = { title: key, content: [] };
if(key.includes(".")) {
delete o.content;
} else if (Object.keys(objMain[key]).length) {
o.content = this.buildResponse(objMain[key]);
}
arr.push(o);
}
return arr;
},
exec: function () {
let targetObject = {};
splittedArray.forEach(arrParent => {
let strObj = '';
for (let i = arrParent.length - 1; i >= 0 ; i--) {
strObj = `"${arrParent[i]}": {${strObj}}`;
}
let parseObj = JSON.parse(`{${strObj}}`);
targetObject = this.mergeObjs(targetObject, parseObj);
});
return this.buildResponse(targetObject);
}
}
}
and use it like this:
const dirs = [
'routes/files',
'routes/files/emptyfolder',
'routes/files/somefolder',
'routes/files/test.docx',
'routes/randomdata.json',
'routes/files/somefolder/example.docx'
];
const data = nestedDirectories(dirs).exec();
result:
[
{
title: 'routes',
content: [
{
title: 'files',
content: [
{ title: 'emptyfolder', content: [] },
{
title: 'somefolder',
content: [ { title: 'example.docx' } ]
},
{ title: 'test.docx' }
]
},
{ title: 'randomdata.json' }
]
}
]
I try to write a function in JavaScript which filter an array by a selected property (an value).
But it works for 2 level only I do not understand what do I missing.
The data I want to filter:
var data = [
{
name: "john_pc",
children: [
{
name: "sabrina_pc",
children: [
{
name: "sabrina_pc"
},
{
name: "john_pc"
}
]
},
{
name: "john_pc"
}
]
},
{
name: "sabrina_pc"
}
]
The childrenFilter funciton :
const childrenFilter = (childrenData, filters) => {
let filteredData = childrenData.filter(item => {
for (var property in filters) {
var optionalValues = filters[property];
var value = item[property];
if (item.children) {
item.children = childrenFilter(item.children, filters);
}
let hasValue = value == optionalValues;
if (hasValue) {
return true;
}
return false;
}
return false;
}, this);
return filteredData;
}
Calling the function:
As you can see the 'childrenFilter' get an object which the key is property in the data and the key is value I want to keep.
let result = childrenFilter(data, {
"name": "a1"
});
console.log(JSON.stringify(result, null, 2))
The wanted result :
[
{
"name": "john_pc",
"children": [
{
"name": "sabrina_pc",
"children": [
{
"name": "john_pc"
}
]
},
{
"name": "john_pc"
}
]
}
]
Your filter function does not take into account whether or not children elements match the pattern, therefore even though some child elements of the object match the pattern, the object itself is being filtered out.
Here is the explanation:
{
name: "a2", // does not match filter {name:'a1} so is removed alongside child objects
children: [ // gets removed with parent object
{
name: "a2"
},
{
name: "a1"
}
]
}
This should produce the desired output:
const childrenFilter = (childrenData, filters) => {
let filteredData = childrenData.filter(item => {
for (var property in filters) {
var optionalValues = filters[property];
var value = item[property];
if (item.children) {
item.children = childrenFilter(item.children, filters);
}
let hasValue = value == optionalValues;
if (hasValue || item.children.length) { // include item when children mathes the pattern
return true;
}
return false;
}
return false;
}, this);
return filteredData;
}
You could build new array for each step of filtering, beginning from the leaves and check if this contains the wanted value.
This approach generates new objects and does not mutate the original data.
function filter(array, filters) {
return array.reduce((r, o) => {
var children = filter(o.children || [], filters);
return children || Object.entries(filters).every(([k, v]) => o[k] === v)
? (r || []).concat(Object.assign({}, o, children && { children }))
: r;
}, undefined);
}
var data = [{ name: "a1", children: [{ name: "a2", children: [{ name: "a2" }, { name: "a1" }] }, { name: "a1" }] }, { name: "b1" }];
console.log(filter(data, { name: "a1" }));
.as-console-wrapper { max-height: 100% !important; top: 0; }