I am new to javascript and json.Basically i have to fetch all keys of nested json object in a parent child relationship heirarchy.The keys are dynamic so I won't necessarily know the keys.
for eg. i have a json
{
"Indo-European": {
"Indo-Iranian": {
"Iranian": [
"Persian",
"Avestan",
"Sogdian",
"Baluchi",
"Kurdish",
"Pashto"
],
"Indic": [
"Assamese",
"Bengali",
"Gujarati",
"Hindi",
"Marathi",
"Punjabi",
"Romany",
"Sindhi",
"Singhalese",
"Urdu"
]
},
"Baltic": [
"Latvian",
"Lithuanian"
]
}
}
output must be-
Indo-European
Indo-European.Indo-Iranian
Indo-European.Indo-Iranian.Iranian
Indo-European.Indo-Iranian.Indic
Indo-European.Baltic
You could do something like this, runs in O(n3) time complexity but works
let json = {
"Indo-European": {
"Indo-Iranian": {
"Iranian": [
"Persian",
"Avestan",
"Sogdian",
"Baluchi",
"Kurdish",
"Pashto"
],
"Indic": [
"Assamese",
"Bengali",
"Gujarati",
"Hindi",
"Marathi",
"Punjabi",
"Romany",
"Sindhi",
"Singhalese",
"Urdu"
]
},
"Baltic": [
"Latvian",
"Lithuanian"
]
}
}
let lv1 = Object.keys(json)
lv1.forEach(i => {
console.log(i)
let lv2 = Object.keys(json[i])
lv2.forEach(j => {
console.log(`--${i}*${j}`)
let lv3 = Object.keys(json[i][j])
lv3.forEach(k => {
if (!json[i][j].hasOwnProperty(length)) {
console.log(`----${i}*${j}*${k}`)
}
})
})
})
Related
I have a data structure as the following
[
{
"models":[
{
"name":"xyz",
"options":[
{
"label":"blue"
},
{
"label":"brown"
},
]
},
{
"name":"abc",
"options":[
{
"label":"yellow"
}
]
},
{
"name":"def",
"options":[
{
"label":"green"
}
]
}
]
}
]
The end result should be an array with all of the labels and name like xyz: blue, xyz: brown, abc: yellow, def: green
so something like this
['xyz: blue', 'xyz: brown', 'abc: yellow','def: green']
I'm trying different approaches, one with RxJS operators and another with reduce
let flat = (acc, current) => {
}
models.reduce(flat, [])
You can use a reduce and a map like this.
const arr = [
{
"models":[
{
"name":"xyz",
"options":[
{
"label":"blue"
},
{
"label":"brown"
},
]
},
{
"name":"abc",
"options":[
{
"label":"yellow"
}
]
},
{
"name":"def",
"options":[
{
"label":"green"
}
]
}
]
}
];
const result = arr[0].models.reduce(
(acc, model) => [...acc, ...model.options.map(i => ({ [model.name]: i.label }))]
, []
);
console.log(result);
If the top level array can have multiple items rather than arr[0] you would need to add another reduce feeding it's accumulator in to the second reduce as it's starting accumulator rather than the empty starting array.
const arr = [
{
"models":[
{
"name":"xyz",
"options":[
{
"label":"blue"
},
{
"label":"brown"
},
]
},
{
"name":"abc",
"options":[
{
"label":"yellow"
}
]
},
{
"name":"def",
"options":[
{
"label":"green"
}
]
}
]
},
{
"models":[
{
"name":"ghi",
"options":[
{
"label":"gold"
},
{
"label":"pink"
},
]
}
]
}
];
const result = arr.reduce(
(acc, item) =>
item.models.reduce(
(acc2, model) => [...acc2, ...model.options.map((i) => ({ [model.name]: i.label }))]
, acc
),
[]
);
console.log(result);
Not sure where RxJs comes into this question but if you are looking to transform an object like this that comes back from a http request you would pipe it into the map operator and then use this function inside the map. If you are looking to do a reduce on a stream there is a reduce operator that emits the accumulator when the source stream completes or the scan operator that emits the accumulator each time the source emits.
Use nested calls to flatMap(), and in the innermost call you concatenate the model name with the option label.
const data = [{
"models": [{
"name": "xyz",
"options": [{
"label": "blue"
},
{
"label": "brown"
},
]
},
{
"name": "abc",
"options": [{
"label": "yellow"
}]
},
{
"name": "def",
"options": [{
"label": "green"
}]
}
]
}];
let result = data.flatMap(d => d.models.flatMap(model => model.options.map(option => `${model.name}: ${option.label}`)));
console.log(result);
Here is using multiple forEach and destructuring
const flat = (arr, res = []) => {
arr.forEach(({ models }) =>
models.forEach(({ name, options }) =>
options.forEach(({ label }) => res.push({ [name]: label }))
)
);
return res;
};
const data = [
{
models: [
{
name: "xyz",
options: [
{
label: "blue",
},
{
label: "brown",
},
],
},
{
name: "abc",
options: [
{
label: "yellow",
},
],
},
{
name: "def",
options: [
{
label: "green",
},
],
},
],
},
];
console.log(flat(data));
const response = array[0].models.reduce((initial, model) => {
if (model.options.length === 1)
initial.push(`${model.name}: ${model.options[0].label}`);
else {
model.options.forEach((option) =>
initial.push(`${model.name}: ${option.label}`),
);
}
return initial;
}, []);
console.log(response)
;
// there is no need if the inner option has just one object you can just access it by model.options[0].label, that why there is a check to see if it one
I have an array of objects that determine which ones should be showed first. An example of this array would be:
[
{
"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870",
"prerequisites_ids": [
"2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"
]
},
{
"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7",
"prerequisites_ids": [
"74e41a2c-e74e-4016-bb2c-f2e84c04fe92"
]
},
{
"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92",
"prerequisites_ids": []
},
{
"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1",
"prerequisites_ids": [
"ef7d2415-808f-4efc-939e-2692f38a5ee7"
]
}
]
How could I sort it to get this?
[
{
"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92",
"prerequisites_ids": []
},
{
"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7",
"prerequisites_ids": [
"74e41a2c-e74e-4016-bb2c-f2e84c04fe92"
]
},
{
"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1",
"prerequisites_ids": [
"ef7d2415-808f-4efc-939e-2692f38a5ee7"
]
},
{
"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870",
"prerequisites_ids": [
"2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"
]
}
]
I have tried creating a custom function:
export function comparePrerequisites(a, b) {
if (!a.prerequisites_ids) {
return -1
}
if (a.prerequisites_ids.includes(b.id)) {
return 1;
}
}
data.sort(comparePrerequisites)
but does not seem to work. Thanks in advance!
We have here the requirements for a topological sort. This is not a job for the sort method. Instead you can use recursion (a DFS traversal) to drill down to a dependency that is already collected, or to a leaf (no dependencies).
Here is an implementation:
function topologicalSort(tasks) {
const visited = new Set;
const taskMap = new Map(tasks.map(task => [task.id, task]));
function dfs(tasks) {
for (let task of tasks) {
if (!visited.has(task.id)) {
dfs(task.prerequisites_ids.map(id => taskMap.get(id)));
}
visited.add(task);
}
}
dfs(tasks);
return [...visited];
}
// Demo on your example:
let tasks = [{"id": "b94ae1a5-c6b2-4e45-87cd-a4036fdb7870","prerequisites_ids": ["2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1"]},{"id": "ef7d2415-808f-4efc-939e-2692f38a5ee7","prerequisites_ids": ["74e41a2c-e74e-4016-bb2c-f2e84c04fe92"]},{"id": "74e41a2c-e74e-4016-bb2c-f2e84c04fe92","prerequisites_ids": []},{"id": "2a4fdd9c-45d0-49d9-a0eb-ba5a0464f2b1","prerequisites_ids": ["ef7d2415-808f-4efc-939e-2692f38a5ee7"]}];
console.log(topologicalSort(tasks));
I'm trying to get into javascript's built-in reduce function and with the help of that build objects inside array.
But you can use whatever function or method you want.
Expected output
[
{ 'team1': [14697807552, 6858384], '2021': [14697807552, 6858384], 'pepsi': [null, null], 'cola': [14697807552, 6858384] },
{ 'team2': [10268029152, 6922128], '2021': [10268029152, 6922128], 'pepsi': [null, 4800], 'cola': [10268029152, 6917328] },
]
What I tried to do
I created a function which takes array as an argument and calls reduce for each array's element.
function transform(arr, obj = {}) {
return arr.reduce((acc, item) => {
const newObj = {};
newObj[item.name] = item.metrics;
acc.push(newObj);
if (item.children) {
transform(item.children, newObj);
}
return acc;
}, []);
}
console.log(transform(arr))
<script>
const arr = [{
"name": "team1",
"metrics": [
14697807552,
6858384
],
"children": [{
"name": "2021",
"metrics": [
14697807552,
6858384
],
"children": [{
"name": "pepsi",
"metrics": [
null,
null
]
},
{
"name": "cola",
"metrics": [
14697807552,
6858384
]
}
]
}]
},
{
"name": "team2",
"metrics": [
10268029152,
6922128
],
"children": [{
"name": "2021",
"metrics": [
10268029152,
6922128
],
"children": [{
"name": "pepsi",
"metrics": [
null,
4800
]
},
{
"name": "cola",
"metrics": [
10268029152,
6917328
]
}
]
}]
}
]
</script>
But it gives me output that I don't want:
[
{ team1: [ 14697807552, 6858384 ] },
{ team2: [ 10268029152, 6922128 ] }
]
If you didn't understand my question or you have question, ask me. Thanks for paying attention!
The transform function doesn't do anything with the second argument obj, and so when you call transform recursively, newObj is not extended: this makes the recursive call losing any desired effect.
Instead of passing that second argument, you could use Object.assign to collect all objects that come back from recursion, and so merge them into one object:
const convert = arr =>
arr?.map(({name, metrics, children}) =>
Object.assign({[name]: metrics}, ...convert(children))) ?? [];
const arr = [{"name": "team1","metrics": [14697807552,6858384],"children": [{"name": "2021","metrics": [14697807552,6858384],"children": [{"name": "pepsi","metrics": [null,null]},{"name": "cola","metrics": [14697807552,6858384]}]}]},{"name": "team2","metrics": [10268029152,6922128],"children": [{"name": "2021","metrics": [10268029152,6922128],"children": [{"name": "pepsi","metrics": [null,4800]},{"name": "cola","metrics": [10268029152,6917328]}]}]}];
console.log(convert(arr));
Please realise that a property like '2021' is an index and will be ordered before other, non-index properties. Even if you print an object like { 'a': 2, '2021': 1 } you'll get the keys in opposite order for that same reason.
If the order of the object keys is important to you, then you should go for an array of pairs in stead of a plain object. Arrays are the structure of choice when you need order, and plain objects should be used when order is not essential.
I have found a bit different solution:)
It is longer than answer from #trincot but also works
const arr = [{"name": "team1","metrics": [14697807552,6858384],"children": [{"name": "2021","metrics": [14697807552,6858384],"children": [{"name": "pepsi","metrics": [null,null]},{"name": "cola","metrics": [14697807552,6858384]}]}]},{"name": "team2","metrics": [10268029152,6922128],"children": [{"name": "2021","metrics": [10268029152,6922128],"children": [{"name": "pepsi","metrics": [null,4800]},{"name": "cola","metrics": [10268029152,6917328]}]}]}];
const handleArr = (list, rez) => {
list.forEach((item) => {
rez[item.name] = item.metrics;
item.children && handleArr(item.children, rez);
});
};
const handle = (list) => {
const rezArr = [];
for (const item of list) {
const rezObj = { [item.name]: item.metrics };
item.children && handleArr(item.children, rezObj);
rezArr.push(rezObj);
}
return rezArr;
};
console.log(handle(arr));
This approahc returns a different result and uses all previous information to get a denormalization of the data.
const
flat = array => array.flatMap(({ name, metrics, children }) => children
? flat(children).map(q => ({ [name]: metrics, ...q }))
: { [name]: metrics }),
data = [{ name: "team1", metrics: [14697807552, 6858384], children: [{ name: "2021", metrics: [14697807552, 6858384], children: [{ name: "pepsi", metrics: [null, null] }, { name: "cola", metrics: [14697807552, 6858384] }] }] }, { name: "team2", metrics: [10268029152, 6922128], children: [{ name: "2021", metrics: [10268029152, 6922128], children: [{ name: "pepsi", metrics: [null, 4800] }, { name: "cola", metrics: [10268029152, 6917328] }] }] }],
result = flat(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I can't seem to find the answer, how to change array in array to object in array ..??
problem this in javaScript. How to convert? How to convert?
I have this array.
[
"or",
[
"or",
{
"status": 1
},
{
"verified": 1
}
],
[
"and",
{
"social_account": 1
},
{
"enable_social": 1
}
]
]
I want this object:
{
"or": [
{
"or": [
{
"status": 1
},
{
"verified": 1
}
]
},
{
"and": [
{
"social_account": 1
},
{
"enable_social": 1
}
]
}
]
}
You can use a recursive function. The base case is when the argument is not an array. In the other case, extract the first array value as key for the object, and map the rest of the array via the recursive function:
const convert = data => Array.isArray(data) && ["or","and"].includes(data[0])
? { [data[0]]: data.slice(1).map(convert) }
: data;
// demo:
let data = ["or",
["or", {"status": 1}, {"verified": 1}],
["and",{"social_account": 1}, {"enable_social": 1}]
];
console.log(convert(data));
I have to array i want to merge them in one array by same id. So every two array have same id should be merged
Case 1:
{
"id":1212,
"instructor":"william",
...
}
Case 2:
[
{
"id":1212,
"name":"accounting",
...
},
{
"id":1212,
"name":"finance",
...
}
]
I need the result to be :
{
"id": 1212,
"instructor": "william",
"Courses": [
{
"id":1212,
"name":"accounting",
...
},
{
"id":1212,
"name":"finance",
...
}
]
}
What you're asking isn't merging, but here is how you can do that.
const instructors = [{ "id":1212, "instructor":"william", }];
const courses = [
{ "id":1212, "name":"accounting" },
{ "id":1212, "name":"finance" }
];
const expected = [{ "id":1212, "instructor":"william", "courses": [
{ "id":1212, "name":"accounting" },
{ "id":1212, "name":"finance" }
]}];
const composed = instructors.map(ins => {
const ret = {...ins};
ret.courses = courses.filter(cou => cou.id === ins.id);
return ret;
});
console.log(composed);
var finArr;
var course = [];
use forEach loop javascript get all value in put your value instead of varid and varname
course.push({"id":varid,"name":varname});
finArr = {"id":variableId,"instructor":variablename,"Courses":course}