I have object with nested fields than named subItem I need to change names of this field to children.
How can this functionality be neatly implemented, perhaps there are ways besides recursion?
let data = [
{
name: 'Alex',
subItem: [
{
name: 'Den',
subItem: [
]
}
]
}
]
function transformData = (data) => {
return data.map(stat=>{
})
}
console.log(transformData(data))
//shoud be
let data = [
{
name: 'Alex',
children: [
{
name: 'Den',
children: []
}
]
}
]
Javascript already includes a recursive object transformer, JSON. stringify with replacer function:
let data = [
{
name: 'Alex',
subItem: [
{
name: 'Den',
subItem: [ {name: 'Foo', subItem: []} ],
}
]
}
]
JSON.stringify(data, function(_, v) {
if (v.subItem) {
v.children = v.subItem
delete v.subItem
}
return v
})
console.log(data)
In the simple case like this, you can also just manipulate the JSON string directly:
newData = JSON.parse(
JSON.stringify(data)
.replaceAll(`"subItem":`, `"children":`))
Related
I have an array that looks something like this:
const arrayObj = [
{
id: 1,
itemsList: [
{
name: "Paul",
},
{
name: "Newman",
},
],
},
{
id: 2,
itemsList: [
{
name: "Jack",
},
{
name: "Man",
},
],
},
]
What I want is to filter the objects whose itemsList contain an object with the name of a certain value. For example, I want to be able to filter out an array with objects whose inner objects with names that contain "ul" (in this case the name Paul contains "ul"), it should give me an output as such:
const outputArray = [
{
id: 1,
itemsList: [
{
name: "Paul",
},
{
name: "Newman",
},
]
}
]
So far, I've only been able to filter out a simple flat array of objects with this function:
function filterByName(array: any, string: any) {
return array.filter((obj: any) =>
["name"].some((key: any) =>
String(obj[key]).toLowerCase().includes(string.toLowerCase())
)
);
}
but I don't know how to apply it to my case.
Here you can use the some method combined with the includes method
const arrayObj = [{
id: 1,
itemsList: [{
name: "Paul",
},
{
name: "Newman",
},
],
},
{
id: 2,
itemsList: [{
name: "Jack",
},
{
name: "Man",
},
],
},
]
const getFilterArray = (name) => {
return arrayObj.filter(obj => obj.itemsList.some(x => x.name.toLowerCase().includes(name.toLowerCase())))
}
console.log(getFilterArray("ul"))
const result = arrayObj.filter(({ itemsList }) =>
itemsList.some(({ name }) => name.toLowerCase().includes('ul')));
Can you try this?
For example
const data = [
{
companies: [
{name: 'Yuri'},
{name: 'Boeing'},
{name: 'Laser'},
],
sectors: [
{name: 'Logistic'},
{name: 'Aviation'},
{name: 'Vocal'},
],
location: [
{name: 'Hong'},
{name: 'Singapore'},
{name: 'Switzerland'},
],
},
];
if a text is searched as 'vocal' how can we search and return value in same format.
This should not be to hard.
Use reduce and filter
See example below
const data = [
{
companies: [{
name: 'Yuri'
},
{
name: 'Boeing'
},
{
name: 'Laser'
},
],
sectors: [{
name: 'Logistic'
},
{
name: 'Aviation'
},
{
name: 'Vocal'
},
],
location: [{
name: 'Hong'
},
{
name: 'Singapore'
},
{
name: 'Switzerland'
},
],
}];
var searchText = "Vocal".toLowerCase();
var result = data.reduce((arr, value) => {
var item = {}
const search=(key)=>{
item[key] = value[key].filter(x => x.name.toLowerCase().indexOf(searchText) != -1);
}
search("companies")
search("sectors")
search("location")
arr.push(item)
return arr;
}, [])
console.log(result)
I would just loop over and filter. Maybe something like this: Search a JavaScript object
It's just a loop on data array and then a loop on each item + return parent if found.
Here is one of many solutions. You have to loop over your data, and filter every entries by their key. It's important to do a .toLowerCase() Comparison.
const data = [
{
companies: [
{ name: 'Yuri' },
{ name: 'Boeing' },
{ name: 'Laser' },
],
sectors: [
{ name: 'Logistic' },
{ name: 'Aviation' },
{ name: 'Vocal' },
],
location: [
{ name: 'Hong' },
{ name: 'Singapore' },
{ name: 'Switzerland' },
],
},
];
const query = 'vocal'
let result = {}
Object.keys(data[0]).forEach(key => {
data[0][key].filter(str => {
if (str.name.toLowerCase() === query.toLowerCase()) {
result = str
}
})
})
console.log(result) // { name: 'Vocal'}
You can use a for-in loop to go through the object keys, and a for-of to go through the array of objects:
const data = [
{
companies: [
{name: 'Yuri'},
{name: 'Boeing'},
{name: 'Laser'},
],
sectors: [
{name: 'Logistic'},
{name: 'Aviation'},
{name: 'Vocal'},
],
location: [
{name: 'Hong'},
{name: 'Singapore'},
{name: 'Switzerland'},
],
},
];
function search() {
let searchVal = document.getElementById('search').value.toLowerCase().trim();
for (let key in data[0]) {
for(obj of data[0][key]) {
if(searchVal == obj.name.toLowerCase()) {
console.log(obj);
return;
}
}
}
console.log("Item was not found.");
}
<input type="text" id="search" value="" />
<input type="button" value="Search" onclick="search()" />
It is not clear to me exactly what you want to be returned, but here is one way to search, within an object, for an object containing a particular case-insensitive string value, not matter how deeply the object is nested.
const search = (object, string) => {
for (const value of Object.values(object)) {
if (typeof value === 'object') {
const result = search(value, string);
if (result !== undefined) return result;
} else if (typeof value === 'string') {
if (value.toLowerCase() === string.toLowerCase()) return object;
}
}
};
search(data, 'vocal'); // { name: "Vocal" }
let ages = data
.filter(isDog)
.map(dogYears)
.reduce(sum);
mL/hr
i want to find the best way of accessing array elements in a javascript object.
Eg: I want to find the first faculty name & first specializations for each course.
var students =
{
deptartment:[
{
name:'Computer Science',
age:20,
Course:[
{ id: 100000
name:'Object Oriented Programming',
faculty:[
{
id:123,
name:'John',
Specialization: [
{name: 'science'},
{name: 'Physics'}
]
}
]
},
{ id: 100001
name:'C#',
faculty:[
{
id:124,
name:'Denis',
Specialization: [
{name: 'Ecnonomics'},
{name: 'Physics'}
]
}
]
}
],
}
]
};
I know i can get the faculty name and specialization by
var courses= deptartment && deptartment.Course ;
var facultyWithSpecialization= {};
if(courses){
courses.forEach(course =>{
var fname = course.faculty && course.faculty[0].name;
var s= course.faculty && course.faculty.Specialization;
facultyWithSpecialization[fname] = s && s[0].name;
})
}
use Object.assign({}, deptartment.Course) instead of department.Course
tried to use the below code but it doesn't make much difference.
var courses=Object.values(Object.assign({}, deptartment.Course));
var fname = Object.values(Object.assign({}, course.faculty[0].Specialization[0]));
Expecting
'John': 'science'
'Denis': 'Ecnonomics'
You can try this. There were many error in the object including spelling mistakes and formatting
var students = {
deptartment: [{
name: 'Computer Science',
age: 20,
Course: [{
id: 100000,
name: 'Object Oriented Programming',
faculty: [{
id: 123,
name: 'John',
Specialization: [{
name: 'science'
},
{
name: 'Physics'
}
]
},
{
id: 124,
name: 'Denis',
Specialization: [{
name: 'Ecnonomics'
},
{
name: 'Physics'
}
]
}
]
}],
}]
}
var obj = {};
students.deptartment.forEach((e) => {
e.Course.forEach((k) => {
k.faculty.forEach((l) => {
obj[l.name] = l.Specialization[0].name
})
})
})
console.log(obj)
I think you meant department instead of deptartment.
I modified a bit your JSON as it was a bit buggy:
var students = {
departments:[
{
name:'Computer Science',
age:20,
Courses:[
{ id: 100000,
name:'Object Oriented Programming',
faculty:[
{
id:123,
name:'John',
Specialization: [
{name: 'science'},
{name: 'Physics'}
]
},
{
id:124,
name:'Denis',
Specialization: [
{name: 'Ecnonomics'},
{name: 'Physics'}
]
}
]
}
],
}]
}
You can use map to achieve this nesting:
students.departments.map(
department => department.Courses.map(
course => course.faculty.map(
student => ({
name: student.name,
specialization: student.Specialization[0].name // check nulls here!
})
)
)
)
I want to filter out a nested array of objects but stuck at the filter part.
How to remove one of the mark?
this.state = {
data: [
{
id: 1,
name: "Main",
subs: [
{
id: "jay",
name: "Jay",
mark: [
{
id: "5a5d84b94a074c49ef2d4553",
name: 100
},
{
id: "5a5d84b94a074119ef2d4553",
name: 70
}
]
}
]
}
]
};
https://codesandbox.io/s/p39momxzp7
I try to use es6 as it's more readable.
expected output
data: [
{
id: 1,
name: "Main",
subs: [
{
id: "jay",
name: "Jay",
mark: [
{
id: "5a5d84b94a074119ef2d4553",
name: 70
}
]
}
]
}
]
Since there are multiple nested arrays in your data structure, you need to use forEach those many times
data.forEach( s => //iterate data
s.subs.forEach( t => //iterate subs
( t.mark = t.mark.slice( 1, 2 ) ) ) ); //slice the second value out
Demo
var data = [{
id: 1,
name: "Main",
subs: [{
id: "jay",
name: "Jay",
mark: [{
id: "5a5d84b94a074c49ef2d4553",
name: 100
},
{
id: "5a5d84b94a074119ef2d4553",
name: 70
}
]
}]
}];
data.forEach(s => s.subs.forEach(t => (t.mark = t.mark.slice(1,2))));
console.log(JSON.stringify(data, 0, 4))
In case the last value should be picked?
data.forEach( s => //iterate data
s.subs.forEach( t => //iterate subs
( t.mark = t.mark.slice( -1 ) ) ) ); //slice the last value out
If you are trying to filter a relevant mark by a given id,
you can combine Array#map and Array#filter to achieve it:
Note that i'm also using the Object Rest/Spread Properties proposal (stage 4)
Running example
const state = {
data: [{
id: 1,
name: "Main",
subs: [{
id: "jay",
name: "Jay",
mark: [{
id: "5a5d84b94a074c49ef2d4553",
name: 100
}, {
id: "5a5d84b94a074119ef2d4553",
name: 70
}]
}]
}]
};
const mark_id = '5a5d84b94a074119ef2d4553';
const nextState = {
...state,
data: state.data.map(obj => {
const filteredSubs = obj.subs.map(sub => {
const markById = sub.mark.filter(m => m.id === mark_id);
return {
...sub,
mark: markById
}
});
return {
...obj,
subs: filteredSubs
}
})
};
console.log(nextState);
You can even use lodash which contains many methods that can be handled easily.
Check if this is what you are looking for. (there is a good scope to refactor it but before that would like to understand if thats what you are looking for)
Below is the code that has been used there.
let inputId = "5a5d84b94a074c49ef2d4553";
let filteredData =_.each(_.cloneDeep(data), function(value, key1) {
_.each(value.subs, function(valueSubs, key2) {
var finalSubMark = _.find(valueSubs.mark, function(eachMark) {
return eachMark.id == inputId;
});
_.set(valueSubs, "mark", finalSubMark);
});
});
https://codesandbox.io/s/v065w05rly
I have a data structure that looks like this
const array = [{
name: 'bar',
children: [{
name: 'foo',
children: [{
name: 'baz123',
}, {
name: 'baz',
}]
}]
}, {
name: 'shallowKey'
}, {
name: 'abc'
}];
And I would like to flatten it to look something like this
[{
name: 'bar'
}, {
name: 'foo',
}, {
name: 'baz123',
}, {
name: 'baz',
}, {
name: 'shallowKey'
}, {
name: 'abc'
}];
I tried lodash like this https://jsfiddle.net/hmzhjji/081q60qg/1/
But it's not doing anything, any other way I can do this?
Thanks
A recursive way would be:
function flatten(array, result = []){
for(const {name, children} of array){
result.push({name});
if(children) flatten(children, result);
}
return result;
}
Or the alternative ES6 version:
const flatten = array => array.reduce((res, {name, children = []}) => res.concat(name).concat(flatten(children)), []);
So you can do flatten(array) to get the desired result.
You can use forEach to iterate over the array and check if the required object is present and call the function recursively
const array = [{
name: 'bar',
children: [{
name: 'foo',
children: [{
name: 'baz123',
}, {
name: 'baz',
}]
}]
}, {
name: 'shallowKey'
}, {
name: 'abc'
}];
var res = [];
function flatten(array){
array.forEach(function(obj){
var name = {name: obj.name}
res.push(name);
if(obj.children){
flatten(obj.children)
}
})
return res;
}
console.log(flatten(array))