Building array recursively in Reactjs - javascript

I am trying to create a menuTree from fetched arrays in React. My problem is that I don't know how to build my array recursively:
Lets say I do a fetch of a mainUrl and get the array:
[
{"id":"EU","type":"l","text":"Europe"},
{"id":"AS","type":"l","text":"Asia"}
]
Since type is "l" i need to do another fetch: mainUrl/EU
Now i get:
[
{"id":"SP","type":"l","text":"Spain"},
{"id":"FR","type":"l","text":"France"}
]
Again both types are "l" so I do another fetch: mainUrl/EU/SP
Now i get:
[
{"id":"MA","type":"t","text":"Madrid"}
]
Since type is now "t" i stop and start again with France and then Asia.
Keeping in mind that i don't know the dept of they children in the array
The my array should look like this:
[
{
"id": "EU",
"type": "l",
"text": "Europe",
"children": [
{
"id": "SP",
"type": "l",
"text": "Spain",
"children":[
{
"id": "MA",
"type": "t",
"text": "Madrid"
}
]
},
{
"id": "FR",
"type": "l",
"text": "France",
"children": [
{
"id": "PA",
"type": "t",
"text": "Paris"
}
]
}
]
},
{
"id": "AS",
"type": "l",
"text": "Asia",
"children":[...]
}
]

const mainUrl = "yourMainUrl";
const fetchDataTree = async url => {
// I assume you will handle the fetch with your own method
let countryArr = await yourFetchFunction(url);
for (let key in countryArr) {
if (countryArr[key].type === "l") {
countryArr[key].children = await fetchDataTree(url + "/" + countryArr[key].id)
}
}
return countryArr
}
const yourDataTree = await fetchDataTree(mainUrl);

const results = fetch("");
function getChildren(name){
const fetchData = fetch(name);
fetchData.forEach(item => {
if (item.type === "l") {
item.children = getChildren(item.id);
}
});
return fetchData;
}
results.forEach(item => {
if (item.type === "l") {
item.children = getChildren(item.id);
}
});
and fetch is like this:
function fetch(u) {
switch (u){
case "":
return [
{
id: "EU",
type: "l",
text: "Europe"
},
{
id: "AS",
type: "l",
text: "Asia"
}
]
case "EU":
return [
{
id:"SP",
type:"l",
text:"Spain"
},
{
id:"FR",
type:"l",
text:"France"
}
];
case "SP":
return [
{
id:"MA",
type:"t",
text:"Madrid"
}
];
default:
return [];
}
};

Related

How to combine multiple JSON object that have same key and value

How to combine JSON objects in the same response that has the same key and value with javascript? This is my data for example:
{
"data": [
{
"name": "A",
"description": {
"location": "location1",
"floor": "floor1",
},
},
{
"name": "A",
"description": {
"location": "location2",
"floor": "floor1",
},
},
{
"name": "B",
"description": {
"location": "location3",
"floor": "floor3",
},
},
]
}
And turn it into this:
{
"data": [
{
"name": "A",
"description": {
"location": ["location1","location2"],
"floor": "floor1",
},
},
{
"name": "B",
"description": {
"location": "location3",
"floor": "floor3",
},
},
]
}
Basically I am someone who is new to learning javascript. Any help would be very helpful, thank you.
You can do:
const data = {data: [{name: 'A',description: {location: 'location1',floor: 'floor1',},},{name: 'A',description: {location: 'location2',floor: 'floor1',},},{name: 'B',description: {location: 'location3',floor: 'floor3',},},],}
const result = {
data: data.data.reduce((a, { name, description }) => {
const index = a.findIndex((d) => d.name === name)
if (index >= 0) {
let location = a[index].description.location
location = Array.isArray(location) ? location : [location]
a[index].description.location = [...location, description.location]
} else {
a.push({ name, description })
}
return a
}, []),
}
console.log(result)
const list = {
"data": [
{
"name": "A",
"description": {
"location": "location1",
"floor": "floor1",
},
},
{
"name": "A",
"description": {
"location": "location2",
"floor": "floor1",
},
},
{
"name": "B",
"description": {
"location": "location3",
"floor": "floor3",
},
},
]
};
const consolidatedData = [];
for (const ele of list.data) {
const isExist = consolidatedData.find(x => x.name === ele.name);
if (!isExist) {
consolidatedData.push({
...ele
})
} else {
const objectKey = consolidatedData.findIndex(x => x.name === ele.name);
if (objectKey > -1) {
const description = consolidatedData[objectKey].description;
const newDes = ele.description;
if (newDes.location !== description.location) {
const data = consolidatedData[objectKey].description;
const added = [data.location, ele.description.location];
delete consolidatedData[objectKey].description.location
consolidatedData[objectKey].description["location"] = added
}
if (newDes.floor !== description.floor){
const data = consolidatedData[objectKey].floor;
const added = [data.floor, ele.description.floor];
delete consolidatedData[objectKey].description.floor
consolidatedData[objectKey].description["floor"] = added
}
}
}
}
console.log(JSON.stringify(consolidatedData, null, 2));
Here is a solution that uses an intermediate bucket object. The desired result object is then constructed from the bucket object:
const input = { "data": [ { "name": "A", "description": { "location": "location1", "floor": "floor1", }, }, { "name": "A", "description": { "location": "location2", "floor": "floor1", }, }, { "name": "B", "description": { "location": "location3", "floor": "floor3", }, }, ] };
let buckets = input.data.reduce((acc, obj) => {
if(!acc[obj.name]) {
acc[obj.name] = {
locations: {},
floors: {}
};
}
acc[obj.name].locations[obj.description.location] = true;
acc[obj.name].floors[obj.description.floor] = true;
return acc;
}, {});
console.log('buckets: ', buckets);
let result = {
data: Object.keys(buckets).map(name => {
let locations = Object.keys(buckets[name].locations);
let floors = Object.keys(buckets[name].floors);
return {
name: name,
description: {
location: locations.length == 1 ? locations[0] : locations,
floor: floors.length == 1 ? floors[0] : floors
}
}
})
};
console.log('result:', result);
Notes:
buckets object:
is created using an array .reduce()
array .reduce() docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
locations and floors are collected using objects instead of arrays, this is to avoid duplicate names
result object:
is using Object.keys(buckets) to get the array of names
.map() transforms each name into the desired object
your unusual array or string value for location and floor is constructed with a conditional

How to filtering out the multiple nested object in Javascript object

Javascript
I have a nested array of objects, I'm trying to filter the given array of objects using a property from the third level of its array property value. For example, from the below array I like to filter the entire array using the property ListId: 10
Example
let test = {
"test":true,
"group":[
{
"name":"header",
"value":[
{
"id":"0",
"list":[
{
"ListId":10,
"name":"string1",
"state":"BY",
"techId":0
},
{
"ListId":11,
"name":"string2",
"state":"BY"
},
{
"ListId":12,
"name":"string3",
"state":"BY"
}
]
}
]
},
{
"name":"header2",
"value":[
{
"id":"01",
"list":[
{
"ListId":100,
"name":"string1",
"state":"BY",
"techId":0
},
{
"ListId":111,
"name":"string2",
"state":"BY"
},
{
"ListId":121,
"name":"string3",
"state":"BY"
}
]
}
]
}
]
}
Filtervalue with ListId = 10
Expected output :
{
"test":true,
"group":[
{
"name":"header",
"value":[
{
"id":"0",
"list":[
{
"ListId":10,
"name":"string1",
"state":"BY",
"techId":0
}
]
}
]
}
]
}
How can I use the filter method using javascript to get this expected result?
You can two it in two times :
First, filter the list arrays,
Secondly filter the groups array using the some method
let test= {
"test": true,
"group": [
{
"name": "header",
"value": [
{
"id": "0",
"list": [
{
"ListId": 10,
"name": "string1",
"state": "BY",
"techId": 0
},
{
"ListId": 11,
"name": "string2",
"state": "BY"
},
{
"ListId": 12,
"name": "string3",
"state": "BY"
}
]
}
]
},
{
"name": "header2",
"value": [
{
"id": "01",
"list": [
{
"ListId": 100,
"name": "string1",
"state": "BY",
"techId": 0
},
{
"ListId": 111,
"name": "string2",
"state": "BY"
},
{
"ListId": 121,
"name": "string3",
"state": "BY"
}
]
}
]
}
]
}
test.group.forEach(group => {
group.value.forEach(value => {
value.list = value.list.filter(list => list.ListId === 10)
})
})
test.group = test.group.filter(group => group.value.some(value => value.list.length > 0))
console.log(test)
Note : You should use plural names for you arrays, it helps understanding the data. For example lists not list for the array.
let z ={"group1": [
{
"name": "header",
"value": [
{
"id": 0,
"list": [
{
"ListId": 10,
"Name": "string1"
},
{
"ListId": 11,
"Name": "string2"
}
]
}
]
}
]}
// This function was written from understading that 'group1' is not a fixed property, but part of a dynamic list due to the number '1'
const getItemByListId = (list, listId) => {
const listKeys = Object.keys(list);
const selectedListKey = listKeys.find(key => {
const groupItems = list[key];
const selectedItem = groupItems.find(({ value: nestedItems }) => {
const selectedNestedItem = nestedItems.find(({ list }) => {
const selectedList = list.find(({ ListId }) => ListId === listId)
return selectedList;
});
return selectedNestedItem;
});
return selectedItem;
});
if (!selectedListKey) {
return null;
}
return list[selectedListKey];
};
console.log(getItemByListId(z, 10));

how to search and retrun value from array

Trying, find and return a value from array using JavaScript- with dynamic inputs
const drawers = [
{
"name": "locations",
"values": [
{
"value": "dana-point-ca",
"label": "Dana Point, CA"
},
{
"value": "bronx-new-york",
"label": "Bronx, New York"
},
{
"value": "new-york-ny",
"label": "New York, NY"
}
]
},
{
"name": "programAreas",
"values": [
{
"value": "coral-conservation",
"label": "CORAL CONSERVATION"
}
]
}
]
Input keys are dynamic, if it is locations and value is bronx-new-york then it should return Bronx, New York;
let lbl = drawers.find(o => o.name === 'string 1').label;
Use array.find in each values until you find the answer.
const drawers = [
{
"name": "locations",
"values": [
{
"value": "dana-point-ca",
"label": "Dana Point, CA"
},
{
"value": "bronx-new-york",
"label": "Bronx, New York"
},
{
"value": "new-york-ny",
"label": "New York, NY"
}
]
},
{
"name": "programAreas",
"values": [
{
"value": "coral-conservation",
"label": "CORAL CONSERVATION"
}
]
}
]
function getLabel(x) {
for (const nameValues of drawers) {
const values = nameValues.values
const item = values.find(v => v.value === x)
if (item !== undefined) {
return item.label
}
}
}
getLabel("bronx-new-york") // 'Bronx, New York'
getLabel("coral-conservation") // 'CORAL CONSERVATION'
getLabel("Value that does not exist") // undefined
for(let i = 0 ; i < drawers.length ; i++){
let lbl = drawers[i].values.find(o => o.label === "Bronx, New York").label;
console.log(lbl)
}
There is a couple of ways to achieve that. As below, you will get all the possible results. However, you might need to deconstruct the arrays in order to get the strings.
const drawers = [
{
"name": "locations",
"values": [
{
"value": "dana-point-ca",
"label": "Dana Point, CA"
},
{
"value": "bronx-new-york",
"label": "Bronx, New York"
},
{
"value": "new-york-ny",
"label": "New York, NY"
}
]
},
{
"name": "programAreas",
"values": [
{
"value": "coral-conservation",
"label": "CORAL CONSERVATION"
}
]
}
]
const enteredValue = "bronx-new-york";
const resultArrays = []
const onSearchLocation = () => {
drawers.find(location => {
const labels = location.values.map((place => {
const array = [];
if(place.value === enteredValue) {
array.push(place.label);
}
if(array.length > 0) {
resultArrays.push(array);
}
}
))
})}
onSearchLocation();
console.log(resultArrays);
I use find with combination of map.
const d = [
{
"name": "locations",
"values": [
{
"value": "dana-point-ca",
"label": "Dana Point, CA"
},
{
"value": "bronx-new-york",
"label": "Bronx, New York"
},
{
"value": "new-york-ny",
"label": "New York, NY"
}
]
},
{
"name": "programAreas",
"values": [
{
"value": "coral-conservation",
"label": "CORAL CONSERVATION"
}
]
}
]
let r = d.find(el => el.name === 'locations').values
let re = r.map(v => {
if (v.value == 'bronx-new-york') {
return v.label
}
})
result = re.filter(e => e)
console.log(result)

Object.assign() for replacing objects of a json

I have JSON looks like this:
{
"ArrayInfo": [
{
"name": "A",
"Id": "1"
},
{
"name": "B",
"Id": "2"
},
{
"name": "C",
"Id": "3"
},
{
"name": "D",
"Id": "4"
}
]
}
I want to replace an object of JSON with another object.For example I have this object :
{"name":"E","Id":"5"}
and it is going to be replaced by this object of JSON:
{"name":"B","Id":"2"}
JSON should look like this :
{
"ArrayInfo": [
{
"name": "A",
"Id": "1"
},
{
"name": "E",
"Id": "5"
},
{
"name": "C",
"Id": "3"
},
{
"name": "D",
"Id": "4"
}
]
}
What I did is to use Object.assign but the new object will be added to array instead of replacing.
(all the data is going to be dynamic but for making more understandable I use static data)
const itemToReplace = { "name": "E", "Id": "5" };
const prevItem = ArrayInfo[2]
ArrayInfo = ArrayInfo.map((el, idx) => {
return Object.assign({}, el, { prevItem: itemToReplace });
});
let NewArryInfo = ArrayInfo
console.log(NewArryInfo)
The result of console.log(NewArryInfo) :
{
"ArrayInfo": [
{
"name": "A",
"Id": "1"
},
{
"name": "B",
"Id": "2"
},
{
"name": "C",
"Id": "3"
},
{
"name": "D",
"Id": "4"
}
{
"name": "E",
"Id": "5"
}
]
}
You can use Array.prototype.splice to replace an item in Array.
const replaceItem = {"name":"E","Id":"5"}
const ArrayInfo = [
{
"name": "A",
"Id": "1"
},
{
"name": "B",
"Id": "2"
},
{
"name": "C",
"Id": "3"
},
{
"name": "D",
"Id": "4"
}
];
ArrayInfo.splice(1, 1, replaceItem); // remove second item and replace
console.log(ArrayInfo);
const object = {
"ArrayInfo": [{
"name": "A",
"Id": "1"
},
{
"name": "B",
"Id": "2"
},
{
"name": "C",
"Id": "3"
},
{
"name": "D",
"Id": "4"
}
]
};
const objectToReplace = {
"name": "B",
"Id": "2"
};
const updatedObject = Object.assign({}, object, {
ArrayInfo: object.ArrayInfo.map((info) => {
if (info.Id === objectToReplace.Id && info.name === objectToReplace.name) {
return {
"name": "E",
"Id": "5"
};
}
return info;
})
});
console.log(updatedObject);
const myArr = [
{
"name": "A",
"Id": "1"
},
{
"name": "B",
"Id": "2"
},
{
"name": "C",
"Id": "3"
},
{
"name": "D",
"Id": "4"
}
];
const replaceObj = (arr, objReplaced, objToReplaceWith) => {
const replacedObjIndex = arr.findIndex(item => JSON.stringify(item) === JSON.stringify(objReplaced));
arr[replacedObjIndex] = objToReplaceWith;
console.log(arr)
return arr;
}
replaceObj(myArr, {"name":"B","Id":"2"}, {"name":"E","Id":"5"});
In this way you can replace any object, from any position in the array.
You won't have to worry about the position of the item that you want to replace in the array and also you won't need to worry about it's keys or values.
When you map over the array you could check if each item is the one you want to replace, and if it is, return the new item instead.
ArrayInfo = ArrayInfo.map((el, idx) => {
if (el.id === prevItem.id && el.name === prevItem.name) {
return itemToReplace;
}
return el;
});
Try this!
let ArrayInfo = [{"name": "A","Id": "1"},{"name": "B","Id": "2"},{"name": "C","Id": "3"},{"name": "D","Id": "4"}];
const onReplace = {"name":"E","Id":"5"};
const toReplace = {"name": "B","Id": "2"};
function replaceArray(array, onReplace, toReplace) {
const removeIndex = array.map(item => { return item.name; }).indexOf(toReplace.name);
array.splice(removeIndex, removeIndex, onReplace);
return array
}
console.log(replaceArray(ArrayInfo, onReplace, toReplace));

node js create an object in specific pattern from array of object

I'm facing some issue in for loop while creating an object from array of object.I have an array as this in node js app:
[
{
"Material": "113/133",
"Name": [
{
"name": "WELD1",
"value": 27520
},
{
"name": "WELD2",
"value": 676992
},
{
"name": "WELD3",
"value": 421
}
]
},
{
"Material": "150/300",
"Name": [
{
"name": "WELD1",
"value": 1441
},
{
"name": "WELD2",
"value": 555
},
{
"name": "WELD3",
"value": 100992
}
]
}
]
I want to return object like this which contains all the Material as array, Name and there value in array of object like this:
{
Material: ["113/133", "150/300"],
datasets: [
{
label: "WELD1",
data: [27520,1441]
},
{
label: "WELD2",
data: [676992,555]
},
{
label: "WELD3",
data: [100,20,0]
}
]
}
I want to get result using for loop.
you can use .reduce() and do something like this:
var arr = [
{
"Material": "113/133",
"Name": [
{
"name": "WELD1",
"value": 27520
},
{
"name": "WELD2",
"value": 676992
},
{
"name": "WELD3",
"value": 421
}
]
},
{
"Material": "150/300",
"Name": [
{
"name": "WELD1",
"value": 1441
},
{
"name": "WELD2",
"value": 555
},
{
"name": "WELD3",
"value": 100992
}
]
}
];
var newArr = arr.reduce((acc, ob) => {
for (var key in ob)
if(typeof acc[key] === 'object')
acc[key] = acc[key] ? acc[key].concat(ob[key]) : [ob[key]];
else
acc[key] ? acc[key].push(ob[key]) : acc[key] = [ob[key]];
return acc;
}, {});
console.log(newArr);
let array = [
{
"Material": "113/133",
"Name": [
{
"name": "WELD1",
"value": 27520
},
{
"name": "WELD2",
"value": 676992
},
{
"name": "WELD3",
"value": 421
}
]
},
{
"Material": "150/300",
"Name": [
{
"name": "WELD1",
"value": 1441
},
{
"name": "WELD2",
"value": 555
},
{
"name": "WELD3",
"value": 100992
}
]
}
]
let answer = {Material: [], datasets: []}
array.forEach(x => {
answer.Material.push(x.Material);
x.Name.forEach(na => {
let object = answer.datasets.find(obj => obj.label === na.name) || {label: "", data: []};
if(object.label === ""){
object.label = na.name;
object.data.push(na.value);
answer.datasets.push(object);
}else{
object.data.push(na.value)
}
});
});
console.log(answer);
The above is alternative solution using forEach instead of reduce
Use of Array.reduce to build your new data structure using data you have
const start = [{
"Material": "113/133",
"Name": [{
"name": "WELD1",
"value": 27520
},
{
"name": "WELD2",
"value": 676992
},
{
"name": "WELD3",
"value": 421
}
]
},
{
"Material": "150/300",
"Name": [{
"name": "WELD1",
"value": 1441
},
{
"name": "WELD2",
"value": 555
},
{
"name": "WELD3",
"value": 100992
}
]
}
];
const end = start.reduce((tmp, {
Material,
Name,
}) => {
// Handle the material
// If it do not exist in the array, push it
if (!tmp.Material.includes(Material)) {
tmp.Material.push(Material);
}
// Handle the datasets
// Look at each Name
Name.forEach(({
name,
value,
}) => {
// Can we find the label?
const labelFind = tmp.datasets.find(y => y.label === name);
// If we can't find the label, create a new dataset
if (!labelFind) {
tmp.datasets.push({
label: name,
data: [
value,
],
});
return;
}
// If we has found it push new value in the dataset
labelFind.data.push(value);
});
return tmp;
}, {
Material: [],
datasets: [],
});
console.log(end);
// This is the old fashioned way.
// Iterate over whole array,
// make a map, push value where 'name' is found in map
// later iterate over this map - dataMap - and form required datasets array.
var Material = [];
var dataMap = {};
arr.forEach(obj => {
Material.push(obj.Material);
obj.Name.forEach(item => {
if(dataMap[item.name]){
dataMap[item.name].push(item.value);
}
else {
dataMap[item.name] = [item.value];
}
});
});
var datasets = [];
Object.keys(dataMap).forEach(label => {
datasets.push({
label: label,
data: dataMap[label]
});
});
var result = {
Material: Material,
datasets: datasets
}
console.log(result);

Categories