Recursively Transform my JSON data with JS - javascript

I'm trying to figure out how to transform some JSON i'm getting back from a web service so i can easily parse it into a nice type-safe object. I want to transform this format from:
[{
"name": "AwesomePeople",
"value": [
[{
"name": "TypeId",
"value": 1
}, {
"name": "People",
"value": [
[{
"name": "id",
"value": 2
}, {
"name": "name",
"value": "Danno"
}
],
[{
"name": "id",
"value": 3
}, {
"name": "name",
"value": "Julio"
}
]
]
}
],
[{
"name": "TypeId",
"value": 2
}, {
"name": "People",
"value": [
[{
"name": "id",
"value": 4
}, {
"name": "name",
"value": "Jenna"
}
],
[{
"name": "id",
"value": 5
}, {
"name": "name",
"value": "Coolio"
}
]
]
}
]
]
}
]
To the following format:
[{
"AwesomePeople": [
[{
"TypeId": 1,
}, {
"People": [
[{
"id": 2
}, {
"firstName":"Danno"
}
],
[{
"id": 3,
}, {
"firstName": "Julio"
}
]
]
}
],
[{
"TypeId": 2
}, {
"People": [
[{
"id": 4
}, {
"firstName": "Jenna"
}
],
[{
"id": 5
}, {
"firstName": "Coolio"
}
]
]
}
]
]
}
];
Two main things need to happen, these stupid "name"/"value" pairs need to be swapped at any and all levels. For example, instead of "name": "id", "value": "3", it would be simply be "id":3. The values are sometimes are arrays, so they need to processed in a similar way...the depth is variable, so i can't assume a certain number of levels deep, so i need to keep processing everything recursively.
I have started playing with the following code...you'll see an empty "newResult" array that i'm trying to build as i traverse the original JSON, taking different action whether i'm currently looking at an object, an array, or a key/property.
let count = 0;
let result = <the original array above>
let newResult = [];
result.forEach(function(resObj) {
console.log("STARTING to TRAVERSE HIGHER LEVEL OBJECTS!");
traverse(resObj);
count++;
//we're done processing high level objects, so return from this function and enjoy the newResult!
if (count===result.length)
//return from this function
console.log(newResult);
console.log("FINISHED PROCESSING HIGHER LEVEL OBJECTS, SO DONE!");
});
//Below are the functions for traversing
function traverse(x, level) {
if (isArray(x)) {
console.log("array");
traverseArray(x);
} else if ((typeof x === 'object') && (x !== null)) {
console.log("object");
traverseObject(x);
} else {
console.log("property: "+x);
//console.log(level + x);
}
}
function isArray(o) {
return Object.prototype.toString.call(o) === '[object Array]';
}
function traverseArray(arr, level) {
//console.log(level + "<array>");
arr.forEach(function(x) {
traverse(x);
});
}
function traverseObject(obj, level) {
var keyName, keyValue;
//console.log(level + "<object>");
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (key==="name"){
keyName = obj[key];
}else if (key==="value"){
keyValue = obj[key];
}
if (keyName && keyValue){
var newObj = {[keyName]: keyValue}
newResult.push(newObj);
//console.log("the KEY NAME IS: "+ keyName + ", and the VALUE is: "+keyValue);
}
//if we have a key value, but the value is an array, stop and
// if (isArray(newOj)
console.log("traversing..." +obj[key]);
traverse(obj[key]);
}//end if property
}//end foreach key in object
}//end traverseObject
thanks all...kudos to the person who can get their brain around this :)

You can do this with JSON.stringify and JSON.parse - with a reviver, check if the value has a name property, and if it does, return { [value.name]: value.value }:
const arr=[{name:"AwesomePeople",value:[[{name:"TypeId",value:1},{name:"People",value:[[{name:"id",value:2},{name:"name",value:"Danno"}],[{name:"id",value:3},{name:"name",value:"Julio"}]]}],[{name:"TypeId",value:2},{name:"People",value:[[{name:"id",value:4},{name:"name",value:"Jenna"}],[{name:"id",value:5},{name:"name",value:"Coolio"}]]}]]}];
const result = JSON.parse(JSON.stringify(arr, (key, value) => (
value?.name
? { [value.name]: value.value }
: value
)));
console.log(result);
If you also want to change the name values to firstName keys, add a conditional in the computed property:
const arr=[{name:"AwesomePeople",value:[[{name:"TypeId",value:1},{name:"People",value:[[{name:"id",value:2},{name:"name",value:"Danno"}],[{name:"id",value:3},{name:"name",value:"Julio"}]]}],[{name:"TypeId",value:2},{name:"People",value:[[{name:"id",value:4},{name:"name",value:"Jenna"}],[{name:"id",value:5},{name:"name",value:"Coolio"}]]}]]}];
const result = JSON.parse(JSON.stringify(arr, (key, value) => (
value?.name
? { [value.name === 'name' ? 'firstName' : value.name]: value.value }
: value
)));
console.log(result);
Manually:
const arr=[{name:"AwesomePeople",value:[[{name:"TypeId",value:1},{name:"People",value:[[{name:"id",value:2},{name:"name",value:"Danno"}],[{name:"id",value:3},{name:"name",value:"Julio"}]]}],[{name:"TypeId",value:2},{name:"People",value:[[{name:"id",value:4},{name:"name",value:"Jenna"}],[{name:"id",value:5},{name:"name",value:"Coolio"}]]}]]}];
const recurse = (val) => {
if (!val || typeof val !== 'object') return val;
if (Array.isArray(val)) return val.map(recurse);
return { [val.name === 'name' ? 'firstName' : val.name]: val.value };
};
const result = recurse(arr);
console.log(result);

I grabbed your data, quickly wrote a function to convert it, came to post it and realized that my output wasn't at all what you requested. I would just throw it away, except that it seems to me this output is much more useful than what you requested. So if you can use something like this:
{
AwesomePeople: [
{
TypeId: 1,
People: [
{id: 2, name: "Danno"},
{id: 3, name: "Julio"}
]
},
{
TypeId: 2,
People: [
{id: 4, name: "Jenna"},
{id: 5, name: "Coolio"}
]
}
]
}
then this function may help:
const convert = (xs) =>
Object .fromEntries (
xs .map (({name, value}) => [
name,
Array .isArray (value) ? value .map (convert) : value
])
)
const data = [{name: "AwesomePeople", value: [[{name: "TypeId", value: 1}, {name: "People", value: [[{name: "id", value: 2}, {name: "name", value: "Danno"}], [{name: "id", value: 3}, {name: "name", value: "Julio"}]]}], [{name: "TypeId", value: 2}, {name: "People", value: [[{name: "id", value: 4}, {name: "name", value: "Jenna"}], [{name: "id", value: 5}, {name: "name", value: "Coolio"}]]}]]}]
console .log (convert (data))
.as-console-wrapper {min-height: 100% !important; top: 0}
If not, well then maybe someone else might get some use out of it.

Here is an answer using object-scan. This code modifies the original input, which can be significantly faster than rebuilding the structure.
Note that in your input the data is a bit inconsistent: Where does firstName come from? So I've assumed consistency
// const objectScan = require('object-scan');
const data = [{ name: 'AwesomePeople', value: [ [{ name: 'TypeId', value: 1 }, { name: 'People', value: [ [{ name: 'id', value: 2 }, { name: 'name', value: 'Danno' } ], [{ name: 'id', value: 3 }, { name: 'name', value: 'Julio' } ] ] } ], [{ name: 'TypeId', value: 2 }, { name: 'People', value: [ [{ name: 'id', value: 4 }, { name: 'name', value: 'Jenna' } ], [{ name: 'id', value: 5 }, { name: 'name', value: 'Coolio' } ] ] } ] ] } ];
objectScan(['**[*].name'], {
filterFn: ({ parent }) => {
const { name, value } = parent;
delete parent.name;
delete parent.value;
parent[name] = value;
}
})(data);
console.log(data);
// => [ { AwesomePeople: [ [ { TypeId: 1 }, { People: [ [ { id: 2 }, { name: 'Danno' } ], [ { id: 3 }, { name: 'Julio' } ] ] } ], [ { TypeId: 2 }, { People: [ [ { id: 4 }, { name: 'Jenna' } ], [ { id: 5 }, { name: 'Coolio' } ] ] } ] ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#14.0.0"></script>
Disclaimer: I'm the author of object-scan

Related

How to convert array of object property?

I'm trying to convert array of objects having value as a array -> into string. I'm facing blocker in this,
let peopleDetails = [
{
name: "raj",
favCar: [{ name: "audi", color: "white" }],
favFood: [{ color: "brown", name: "Idli" }],
},
{ name: "deepak", place: "India", favPlace: [{ name: "Tajmahal" }] },
];
I need structure like,
let peopleDetails = [
{ name: "raj", favCar: "audi", favFood: "Idli" },
{ name: "deepak", place: "India", favPlace: "Tajmahal" },
];
For what I understand you want the value of every property to become the name value of its first element, when the value is an array of object.
Here's an immutable solution that follows this concept:
let peopleDetails = [
{
name: 'raj',
favCar: [{ name: 'audi', color: 'white' }],
favFood: [{ name: 'Idli' }],
},
{ name: 'deepak', place: 'India', favPlace: [{ name: 'Tajmahal' }] },
];
const result = peopleDetails.map(obj =>
Object.fromEntries(Object.entries(obj).map(([key, value]) =>
[key, value?.[0]?.name ?? value]
))
);
console.log(result);
I'm not sure why you've got arrays of singular elements (favourites typically don't have second or third places) so if you just want to extract the name from each item that's an array, take it from the first element in each array:
let peopleDetails = [{
name: "raj",
favCar: [{
name: "audi",
color: "white"
}],
favFood: [{
name: "Idli"
}],
},
{
name: "deepak",
place: "India",
favPlace: [{
name: "Tajmahal"
}]
},
];
let peopleDetailsModified = peopleDetails.map(o => {
let retObj = {};
for (key in o) {
if (Array.isArray(o[key])) {
retObj[key] = o[key][0].name;
} else {
retObj[key] = o[key];
}
}
return retObj;
});
console.log(peopleDetailsModified);
I've made this code more verbose than it needs to be, it's quite easy to one-line it using reduce.
I'm also quite not sure what you're trying to achieve as the other answers but I tried to make a map of the current object to an object that is more to your liking. I formatted it a little so you can see what I did:
peopleDetails.map(item => {
return {
name: item.name,
place: item.place,
favCar: item.favCar ? item.favCar[0].name : "",
favPlace: item.favPlace ? item.favPlace[0].name : "",
favFood: item.favFood ? item.favFood[0].name : ""}});
I have ran the code and its a generic code for similar data
const _ = require('lodash')
const peopleDetails =[
{
"name": "raj",
"favCar": [
{
"name": "audi",
"color": "white"
}
],
"favFood": [
{
"name": "Idli"
}
]
},
{
"name": "deepak",
"place": "India",
"favPlace": [
{
"name": "Tajmahal"
}
]
}
]
const newPeopleDetails = peopleDetails.map(obj => {
const formObj = {
favCar: obj && obj.favCar && obj.favCar[0].name,
favFood: obj && obj.favFood && obj.favFood[0].name,
favPlace: obj && obj.favPlace && obj.favPlace[0].name
}
const finalObj = _.pickBy(formObj, _.identity);
return Object.assign({}, obj, finalObj);
});
console.log(newPeopleDetails)

Map over nested array but return an array of the numbers in React

Following on from this question
I would like to return the point?.value as an array of numbers, I have tried let data = point?.value + 1
So far my code is:
Data structure:
export const testData = [
{
"date": [
"2016-09-0912:00:00",
"2015-09-0913:10:00"
],
"title": [
{
"name": 'Name 1',
"description": [
{
"value": 7898
},
{
"value": 7898
}
]
},
{
"name": 'Name 2',
"description": [
{
"value": 3244
},
{
"value": 4343
}
]
},
{
"name": 'Name 3',
"description": [
null,
null
]
}
]
}
]
map function:
<div style={{ color: 'white' }}>
Hello
{testData.map(inner => {
return (
<p style={{color: 'white'}}>{inner.title.map(inside => {
return (
inside.description.map(point => {
return (
point?.value
)
})
)
})}</p>
)
})}
You can use Array.prototype.flatMap():
The flatMap() method returns a new array formed by applying a given callback function to each element of the array, and then flattening the result by one level.
const testData = [
{
date: ["2016-09-0912:00:00", "2015-09-0913:10:00"],
title: [
{
name: "Name 1",
description: [{ value: 7898 }, { value: 7898 }],
},
{
name: "Name 2",
description: [{ value: 3244 }, { value: 4343 }],
},
{
name: "Name 3",
description: [null, null],
},
],
},
];
const output = testData
.flatMap((inner) => {
return inner.title.flatMap((inside) =>
inside.description.map((point) => point?.value)
);
})
.filter((v) => typeof v !== "undefined");
console.log("output: ", output);
Result:
output: [ 7898, 7898, 3244, 4343 ]

how to filter array object using object array

I have a filtering group js object like this :
let filter = {
generalFilter:[
{key: "connected", value: true},
{key: "connected", value: false}
],
locationFilter:[
{key: "deviceLocation", value: "def"},
{key: "deviceLocation", value: "abc"}
],
paymentMethodsFilter:[
{key: "devicePaymentMethods", value: "ab"}
]
}
and the main array like this:
const devices = [{
deviceLocation: {
label: "abc",
value: "abc"
},
deviceName: "test7",
devicePaymentMethods: [{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}, {
label: "ef",
value: "ef"
}],
deviceType: "iPad",
id: "001",
connected: true,
enabled: true,
},
{
deviceLocation: {
label: "def",
value: "def"
},
deviceName: "test4",
devicePaymentMethods: [{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}],
deviceType: "iPad",
id: "004",
connected: false,
enabled: false,
}
];
how can I filter this devices array using filter object?
this is what I tried but it doesn't work
devices.filter((device) => {
let shouldKeep = new Array(3)
shouldKeep.fill(0) //fills the array with 0, meaning no filter groups has passed yet
for(let filterGroupIndex in filter) {// Loop through each filter group in filter
let filterGroup = filter[filterGroupIndex]
for(let filterObject in filterGroup) { //Loop through
if(filterGroup[filterObject].key in device && device[filterGroup[filterObject].key] === filterGroup[filterObject].value) {
shouldKeep[filterGroupIndex] = 1 //Set current filterGroup to 1, meaning it has passed the filter
break; // At least one value in that filter group is true, skip to next filter group
}
}
}
if(shouldKeep.reduce((a,b) => a + b, 0) >= filter.length) {
return true;
}
return false
})
sometimes this filter object can be empty when its empty it should return full array without filter main array. what is the best approach to do this? I'm not sure about this maybe there is another solution for this. please help me
the default filter object is like this
let filter = {
generalFilter:[],
locationFilter:[],
paymentMethodsFilter:[]
}
the user can add an object to that filter array I'm using react hooks
for example
let filter = {
generalFilter:[
{key: "connected", value: true},
{key: "connected", value: false}
],
locationFilter:[],
paymentMethodsFilter:[]}
then we have to check both connected: false and connected: true match data in the main array (if data has connected: true in the main array then it will show and also if data has connected: false it will show)
for this type of filter
let filter = {
generalFilter:[
{key: "connected", value: true},
{key: "connected", value: false}
],
locationFilter:[
{key: "deviceLocation", value: "def"},
{key: "deviceLocation", value: "abc"}
],
paymentMethodsFilter:[
{key: "devicePaymentMethods", value: "ab"}
]
}
result should be
result =[{
deviceLocation: {
label: "abc",
value: "abc"
},
deviceName: "test7",
devicePaymentMethods: [{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}, {
label: "ef",
value: "ef"
}],
deviceType: "iPad",
id: "001",
connected: true,
enabled: true,
},
{
deviceLocation: {
label: "def",
value: "def"
},
deviceName: "test4",
devicePaymentMethods: [{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}],
deviceType: "iPad",
id: "004",
connected: false,
enabled: false,
}
];
because u can see in filter connected:true and connected :false and deviceLocation with def and abc and also devicePaymentMethods is ab
it's mean I want all devices with connected true and connected false with location abc and def and paymetmethod ab
Check comments for explanation.
const filter = {
generalFilter: [
{key: "connected", value: true},
{key: "connected", value: false}
],
locationFilter: [
{key: "deviceLocation", value: "def"},
{key: "deviceLocation", value: "abc"}
],
paymentMethodsFilter: [
{key: "devicePaymentMethods", value: "ab"}
]
};
const parsedFilter = {};
/**
converting filter into a hashmap with a filter as a Key and value as an
array of possible values.
parsedFilter looks like this
{"connected":[true,false],"deviceLocation":["def","abc"],"paymentOption":["ab"]}
now we can easily check if any value is present in the filter.
**/
const filterKeys = Object.keys(filter);
filterKeys.forEach((filterKey) => {
if (Array.isArray(filter[filterKey])) {
filter[filterKey].forEach((filterItem) => {
if (Object.prototype.hasOwnProperty.call(parsedFilter, filterItem.key)) {
parsedFilter[filterItem.key].push(filterItem.value);
} else {
parsedFilter[filterItem.key] = [filterItem.value];
}
});
}
});
const devices = [
{
deviceLocation: {
label: "abc",
value: "abc"
},
deviceName: "test7",
devicePaymentMethods: [
{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}, {
label: "ef",
value: "ef"
}],
deviceType: "iPad",
id: "001",
connected: true,
enabled: true,
}
];
const result = [];
/**
Looping through each device and check if that key is present in the
parsedFilter.
if true: check for typeof value for that device key.
if Object: then check if it is present in the array of not for the
givem deviceKey in parsedFilter.
if Array: then loop through each item and check if it is present
in the parsedFilter for the given deviceKey
if Number, string, boolean: Check if is present in the
parsedFilter for the given deviceKey
if false: simply add it to the result.
**/
if (Array.isArray(devices)) {
devices.forEach((device) => {
const keys = Object.keys(device);
const resultDeviceObj = {};
keys.forEach((key) => {
if (Object.prototype.hasOwnProperty.call(parsedFilter, key)) {
if (typeof device[key] === "object" && parsedFilter[key].includes(device[key].value)) {
resultDeviceObj[key] = device[key];
} else if (Array.isArray(device[key])) {
const arrayResult = [];
device[key].forEach((item) => {
if (parsedFilter[key].includes(item.value)) {
arrayResult.push(item);
}
});
resultDeviceObj[key] = arrayResult;
} else if(parsedFilter[key].includes(device[key])) {
resultDeviceObj[key] = device[key];
}
} else {
resultDeviceObj[key] = device[key];
}
});
result.push(resultDeviceObj);
});
}
console.log("result", result);
Edit
const filter = {
generalFilter: [{key: "connected", value: true}],
locationFilter: [{key: "deviceLocation", value: "abcd"}],
paymentMethodsFilter: [{key: "devicePaymentMethods", value: "ab"}]
};
const parsedFilter = {};
const filterKeys = Object.keys(filter);
filterKeys.forEach((filterKey) => {
if (Array.isArray(filter[filterKey])) {
filter[filterKey].forEach((filterItem) => {
if (Object.prototype.hasOwnProperty.call(parsedFilter, filterItem.key)) {
parsedFilter[filterItem.key][filterItem.value] = filterItem.value;
} else {
parsedFilter[filterItem.key] = {
[filterItem.value]: filterItem.value
}
}
});
}
});
//{"connected":{"true": true,"false": "false"},"deviceLocation":{"def": "def","abc": "abc"},"paymentOption":{"ab": "ab"}}
const devices = [{
deviceLocation: {
label: "abc",
value: "abc"
},
deviceName: "test7",
devicePaymentMethods: [{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}, {
label: "ef",
value: "ef"
}],
deviceType: "iPad",
id: "001",
connected: true,
enabled: true,
},
{
deviceLocation: {
label: "def",
value: "def"
},
deviceName: "test4",
devicePaymentMethods: [{
label: "ab",
value: "ab"
}, {
label: "cd",
value: "cd"
}],
deviceType: "iPad",
id: "004",
connected: false,
enabled: false,
}
];
const result = [];
const isObject = function (a) {
return a.constructor.toString().indexOf("Object") !== -1;
};
if (Array.isArray(devices)) {
devices.forEach((device) => {
const keys = Object.keys(device);
let isValid = true;
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (Object.prototype.hasOwnProperty.call(parsedFilter, key)) {
if (isObject(device[key]) &&
!Object.prototype.hasOwnProperty.call(parsedFilter[key], device[key].value)) {
isValid = false;
break;
} else if (Array.isArray(device[key])) {
isValid = false;
for (let j = 0; j < device[key].length; j++) {
const item = device[key][j];
if (Object.prototype.hasOwnProperty.call(parsedFilter[key], item.value)) {
isValid = true;
break;
}
}
if (!isValid) {
break;
}
} else if (typeof device[key] === "boolean" &&
!Object.prototype.hasOwnProperty.call(parsedFilter[key], device[key])) {
isValid = false;
break;
}
}
}
if (isValid) {
result.push(device);
}
}
);
}
console.log("result", result)
Can you explain more what you are trying to do. It is very unclear from your question.
In general you would do something like this if you want to filter by device location.
devices.filter(device=>device.deviceLocation.label==="abc")
I hope this example will help you figure out the rest.

How to efficiently construct new object array using unique values from arrays of children inside an array of parent objects

The need is to take objects like this:
[ { "first":
{ "children" : [{ "name": "abc", "detail":"123"},
{ "name": "def", "detail":"456"}
]
}},
{ "second":
{ "children" : [{ "name": "ghi", "detail":"123"},
{ "name": "jkl", "detail":"456"}
]
}},
{ "third":
{ "children" : [{ "name": "mno", "detail":"123"},
{ "name": "pqr", "detail":"456"}
]
}},
{ "fourth":
{ "children" : [{ "name": "stu", "detail":"123"},
{ "name": "vwx", "detail":"456"}
]
}},
{ "fifth":
{ "children" : [{ "name": "yz", "detail":"123"},
{ "name": "abc", "detail":"456"}
]
}},
{ "sixth":
{ "children" : [{ "name": "def", "detail":"123"},
{ "name": "ghi", "detail":"456"}
]
}}
]
and then create a flattened array of unique values (options for a select) from the name field of the children that looks like this:
[{"value":"abc", "label":"abc"},
{"value":"def", "label":"def"},
{"value":"ghi", "label":"ghi"},
{"value":"jkl", "label":"jkl"},
{"value":"mno", "label":"mno"},
{"value":"pqr", "label":"pqr"},
{"value":"stu", "label":"stu"},
{"value":"vwx", "label":"vwx"},
{"value":"yz", "label":"yz"}
]
The code below is working, but it looks like it is inefficient because it appears to make many passes over the array:
[
...new Set(
[].concat.apply([], bases.map((base) => {
if (!base.children || base.children.length === 0) return;
return base.children}
)).map((child) => child.name)
)
].map((optName) => {return {value: optName, label: optName};})
If it is possible, how can this same result be achieved without as many iterations across the array.
Firstly, as a rule of thumb, you shouldn't worry too much about performance until you have a reason to do so.
Secondly, chaining the array prototype functions (e.g. map, forEach, filter) will require multiple iterations by design.
Thirdly, there's no reason to assume multiple iterations is slower than a single iteration if the work done within the iterations is the same anyways. I.e. incrementing an index and comparing it with an array length isn't going to be the bottleneck compared to pushing objects into arrays and check set entries.
Here's a (IMO) cleaner snippet to extract unique names from your array:
let bases = [{
children: [{
name: "abc",
detail: "123"
},
{
name: "def",
detail: "456"
}
]
}, {
children: [{
name: "abc" ,
detail: "123"
},
{
name: "xyz" ,
detail: "456"
}
]
},
{}
];
let output = bases
.flatMap(b => b.children || [])
.map(c => c.name)
.filter((v, i, a) => a.indexOf(v) === i) // filter unique values
.map(name => ({
value: name,
label: name,
}));
console.log(output);
Now if you really want to do all this in a single iteration, that too is possible, but harder to read:
let bases = [{
children: [{
name: "abc",
detail: "123"
},
{
name: "def",
detail: "456"
}
]
}, {
children: [{
name: "abc" ,
detail: "123"
},
{
name: "xyz" ,
detail: "456"
}
]
},
{}
];
let output = [];
let seenNames = {};
for (base of bases) {
if (!base.children)
continue;
for (child of base.children) {
let name = child.name;
if (seenNames[name])
continue;
seenNames[name] = true;
output.push({
value: name,
label: name,
});
}
}
console.log(output);
You could take Array#flatMap for getting a flat representation of data for using unique values and map new objects.
var data = [{ first: { children: [{ name: "abc", detail: "123" }, { name: "def", detail: "456" }] } }, { second: { children: [{ name: "ghi", detail: "123" }, { name: "jkl", detail: "456" }] } }, { third: { children: [{ name: "mno", detail: "123" }, { name: "pqr", detail: "456" }] } }, { fourth: { children: [{ name: "stu", detail: "123" }, { name: "vwx", detail: "456" }] } }, { fifth: { children: [{ name: "yz", detail: "123" }, { name: "abc", detail: "456" }] } }, { sixth: { children: [{ name: "def", detail: "123" }, { name: "ghi", detail: "456" }] } }],
result = Array.from(
new Set(data
.flatMap(Object.values)
.flatMap(({ children }) => children.map(({ name }) => name))
),
value => ({ value, label: value })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to place others name object to last position of the array?

I have a object of array which is give below -
arrayData = [
{label:"data",value:"data"},
{label:"data",value:"data"},
{label:"Others",value:"Others"},
{label:"data",value:"data"},
]
and want to shift the others object at the last position of the array and i also don't know the index value of that object.
Thankyou
You can filter it out first and push then into the end:
var arrayData = [
{label:"data",value:"data"},
{label:"data",value:"data"},
{label:"Others",value:"Others"},
{label:"data",value:"data"},
]
var res = arrayData.filter(x => x.label !== 'Others');
res.push(arrayData.find(x => x.label === 'Others'));
console.log(res);
i also don't know the index value of that object
for that you can use findIndex. First get the index of the required object , and in another variable get the last object in the array. Then swap their place
var arrayData = [{
label: "data",
value: "data"
},
{
label: "data",
value: "data"
},
{
label: "Others",
value: "Others"
},
{
label: "data",
value: "data"
},
]
let findIndex = arrayData.findIndex(function(item) {
return item.label === 'Others' && item.value === 'Others'
})
let storeLastVal = arrayData[arrayData.length - 1];
let otherVal = arrayData[findIndex]
arrayData[findIndex] = storeLastVal;
arrayData[arrayData.length - 1] = otherVal;
console.log(arrayData)
You could get the index first, splice this item and push the spreaded array.
var array = [{ label: "data", value: "data" }, { label: "data", value: "data" }, { label: "Others", value: "Others" }, { label: "data", value: "data" }],
index = array.findIndex(({ value }) => value === 'Others');
array.push(...array.splice(index, 1));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Well you can first parse the array and create two arrays, one with the elements that will stay in place, the other with the elements that will be placed at the end. Then you can join those 2 arrays.
arrayData = [
{label:"data",value:"data"},
{label:"data",value:"data"},
{label:"Others",value:"Others"},
{label:"data",value:"data"},
]
var startValues = [];
var endValues = [];
arrayData.forEach((value) => {
if (value.label === "Others") {
endValues.push(value);
} else {
startValues.push(value);
}
});
arrayData = startValues.concat(endValues);
Or you can use recursion. This program has a distinct advantage in that it doesn't have to find the element (or index) before beginning the computation -
const data =
[ { label: "data", value: "data" }
, { label: "data", value: "data" }
, { label: "Others", value: "Others" }
, { label: "data", value: "data" }
]
const transform = ([ a, ...rest ]) =>
a === undefined
? []
: a.label === "Others"
? [ ...transform (rest), a ]
: [ a, ...transform (rest) ]
console .log (transform(data))
// [ { label: "data", value: "data" }
// , { label: "data", value: "data" }
// , { label: "data", value: "data" }
// , { label: "Others", value: "Others" }
// ]
Obviously you should probably make "Others" a parameter of the function -
const data =
[ { label: "data", value: "data" }
, { label: "data", value: "data" }
, { label: "Others", value: "Others" }
, { label: "data", value: "data" }
]
const transform = (query, [ a, ...rest ]) =>
a === undefined
? []
: a.label === query
? [ ...transform (query, rest), a ]
: [ a, ...transform (query, rest) ]
console .log (transform ("Others", data))
// [ { label: "data", value: "data" }
// , { label: "data", value: "data" }
// , { label: "data", value: "data" }
// , { label: "Others", value: "Others" }
// ]
console .log (transform ("data", data))
// [ { label: "Others", value: "Others" }
// , { label: "data", value: "data" }
// , { label: "data", value: "data" }
// , { label: "data", value: "data" }
// ]
Note, the original input is not mutated. If multiple labels are found matching the query, all of them will be moved to the end of the array.

Categories