Related
Suppose I have a Nested array of objects like below:
let a = [{
title: "A123",
book: "A",
tags: [{
key: "Romantic",
ID: 1
}, {
key: "Sad",
ID: 2
},{
key: "Strange",
ID: 3
}]
}, {
title: "B123",
book: "B",
tags: [{
key: "Parody",
ID: 1
}, {
key: "Romantic",
ID: 2
},{
key: "Happy",
ID: 3
}]
}, {
title: "C123",
book: "C",
tags: [{
key: "Dark",
ID: 1
}, {
key: "Science Fiction",
ID: 2
}]
}, {
title: "D123",
book: "D",
tags: [{
key: "New Life",
ID: 1
}, {
key: "Science Fiction",
ID: 2
}]
}]
Now I am trying to get the output of those objects which does not contain the tags as 'Romantic'.
** Expected Output:**
{
title: "C123",
book: "C",
tags: [{
key: "Dark",
ID: 1
}, {
key: "Science Fiction",
ID: 2
}]
}, {
title: "D123",
book: "D",
tags: [{
key: "New Life",
ID: 1
}, {
key: "Science Fiction",
ID: 2
}]
}
I have tried the below from my end but it is returning all the elements. Is there a way to achieve the expected output?
a.filter( (ele) => ele.tags.filter( (eachTags) => eachTags.key !== 'Romantic'))
You can use every instead of the 2nd filter:
a.filter(book => book.tags.every(tag => tag.key !== "Romantic"));
Which is saying filter the array and exclude a book where any tag is Romantic.
Example:
let a = [{
title: "A123",
book: "A",
tags: [{
key: "Romantic",
ID: 1
}, {
key: "Sad",
ID: 2
},{
key: "Strange",
ID: 3
}]
}, {
title: "B123",
book: "B",
tags: [{
key: "Parody",
ID: 1
}, {
key: "Romantic",
ID: 2
},{
key: "Happy",
ID: 3
}]
}, {
title: "C123",
book: "C",
tags: [{
key: "Dark",
ID: 1
}, {
key: "Science Fiction",
ID: 2
}]
}, {
title: "D123",
book: "D",
tags: [{
key: "New Life",
ID: 1
}, {
key: "Science Fiction",
ID: 2
}]
}];
let notRomantic = a.filter(book => book.tags.every(tag => tag.key !== "Romantic"));
console.log(notRomantic);
Alternatively you could use Array.prototype.some():
let a = [
{title: "A123",book: "A",tags: [{key: "Romantic",ID: 1}, {key: "Sad",ID: 2},{key: "Strange",ID: 3}]},
{title: "B123",book: "B",tags: [{key: "Parody",ID: 1}, {key: "Romantic",ID: 2},{key: "Happy",ID: 3}]},
{title: "C123",book: "C",tags: [{key: "Dark",ID: 1}, {key: "Science Fiction",ID: 2}]},
{title: "D123",book: "D",tags: [{key: "New Life",ID: 1}, {key: "Science Fiction",ID: 2}]}]
console.log(a.filter(o=>!o.tags.some(t=>t.key==="Romantic")))
you can achieve this result using filter and some
const result = a.filter((obj) => !obj.tags.some((o) => o.key === "Romantic"));
let a = [
{
title: "A123",
book: "A",
tags: [
{
key: "Romantic",
ID: 1,
},
{
key: "Sad",
ID: 2,
},
{
key: "Strange",
ID: 3,
},
],
},
{
title: "B123",
book: "B",
tags: [
{
key: "Parody",
ID: 1,
},
{
key: "Romantic",
ID: 2,
},
{
key: "Happy",
ID: 3,
},
],
},
{
title: "C123",
book: "C",
tags: [
{
key: "Dark",
ID: 1,
},
{
key: "Science Fiction",
ID: 2,
},
],
},
{
title: "D123",
book: "D",
tags: [
{
key: "New Life",
ID: 1,
},
{
key: "Science Fiction",
ID: 2,
},
],
},
];
const result = a.filter((obj) => !obj.tags.some((o) => o.key === "Romantic"));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have this array of deeply nested objects
[
{
id: 1,
name: "task 1",
wbs: 1
children: [
{
id: 2,
name: "task 1.1",
wbs: 1.1
children: []
}
]
},
{
id: 1,
name: "task 2",
wbs: 2
children: [
{
id: 2,
name: "task 2.1",
wbs: 2.1
children: [
{
id: 2,
name: "task 2.1.1",
wbs: 2.1.1
children: []
}
]
}
]
},
{
id: 1,
name: "task 3",
wbs: 3
children: []
},
]
The wbs number should be generated according to the position and depth the object is at. How can I generate this number when I push a new object to the array.
That is, if I push a new object to the children array of task 1, the wbs number should be 1.2. How can I achieve this?
Because arrays keep a reliable insertion order, we can do this rather easily actually! We can even create a simple prototype function to streamline this process if you're doing this often in your project:
let obj = [
{ id: 1, name: "task 1", wbs: "1", children: [ { id: 2, name: "task 1.1", wbs: "1.1", children: [] } ] },
{ id: 1, name: "task 2", wbs: "2", children: [ { id: 2, name: "task 2.1", wbs: "2.1", children: [ { id: 2, name: "task 2.1.1", wbs: "2.1.1", children: [] } ] } ] },
{ id: 1, name: "task 3", wbs: "3", children: [] }
];
Array.prototype.wbsPush = function() {
const array = this;
if (!array.every(el => el.wbs)) return false;
const previousWbs = array[array.length - 1].wbs;
const newWbs = previousWbs.split('.').reverse().map((e,i) => i ? e : parseInt(e) + 1).reverse().join('.');
array.push({ id: array[array.length - 1].id + 1, name: `task ${newWbs}`, wbs: newWbs, children: [] });
}
obj.wbsPush(); // -> wbs: 4
obj[0].children.wbsPush(); // -> wbs: 1.2
console.log(obj);
Can you help me please to flat this tree?
I have tried a few things and it didn't work.
I would like to get the fastest way(Algorithm).
const source = [
{
item: { id: 1, name: "item name", code: "1d4g4" },
children: [
{
item: { id: 2, name: "item name 2", code: "1d4g4" },
children: [
{
item: { id: 2, name: "item name 2", code: "1d4g4" },
children: [
{
item: { id: 3, name: "item name 2", code: "1d4g4" },
children: [
{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] },
{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] },
{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] },
],
},
],
},
],
},
],
},
];
This is result that i expect to have:
{ id: 1, name: 'item name', code: '1d4g4' },
{ id: 2, name: 'item name 2', code: '1d4g4' },
{ id: 2, name: 'item name 2', code: '1d4g4' },
{ id: 3, name: 'item name 2', code: '1d4g4' },
{ id: 4, name: 'item name 2', code: '1d4g4' },
{ id: 4, name: 'item name 2', code: '1d4g4' },
{ id: 4, name: 'item name 2', code: '1d4g4' }
]```
You could take Array#flatMap and a callback which calls itself.
const
flat = ({ item, children = [] }) => [item, ...children.flatMap(flat)],
data = [{ item: { id: 1, name: "item name", code: "1d4g4" }, children: [{ item: { id: 2, name: "item name 2", code: "1d4g4" }, children: [{ item: { id: 2, name: "item name 2", code: "1d4g4" }, children: [{ item: { id: 3, name: "item name 2", code: "1d4g4" }, children: [{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] }, { item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] }, { item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] }] }] }] }] }],
result = data.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
After fixing your syntax to be actually valid JavaScript, you'll need a recursive function:
function flatten(destArray, nodeList) {
nodeList.forEach((node) => {
destArray.push(node.item);
flatten(destArray, node.children || []);
});
}
const source = [
{
item: { id: 1, name: "item name", code: "1d4g4" },
children: [
{
item: { id: 2, name: "item name 2", code: "1d4g4" },
children: [
{
item: { id: 2, name: "item name 2", code: "1d4g4" },
children: [
{
item: { id: 3, name: "item name 2", code: "1d4g4" },
children: [
{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] },
{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] },
{ item: { id: 4, name: "item name 2", code: "1d4g4" }, children: [] },
],
},
],
},
],
},
],
},
];
const dest = [];
flatten(dest, source);
console.log(dest);
outputs
[
{ id: 1, name: 'item name', code: '1d4g4' },
{ id: 2, name: 'item name 2', code: '1d4g4' },
{ id: 2, name: 'item name 2', code: '1d4g4' },
{ id: 3, name: 'item name 2', code: '1d4g4' },
{ id: 4, name: 'item name 2', code: '1d4g4' },
{ id: 4, name: 'item name 2', code: '1d4g4' },
{ id: 4, name: 'item name 2', code: '1d4g4' }
]
You could write an internal visit method to handle traversing the tree and adding items to an internal results list.
Note: Make sure your JS/JSON data is structured correctly.
const tree = [{
item: {id: 1, name: "item name", code: "1d4g4"},
children: [{
item: {id: 2, name: "item name 2", code: "1d4g4"},
children: [{
item: {id: 2, name: "item name 2", code: "1d4g4"},
children: [{
item: {id: 3, name: "item name 2", code: "1d4g4"},
children:[
{item: {id: 4, name: "item name 2", code: "1d4g4"}, children: []},
{item: {id: 4, name: "item name 2", code: "1d4g4"}, children: []},
{item: {id: 4, name: "item name 2", code: "1d4g4"}, children: []},
]
}]
}]
}]
}];
const treeToList = (tree, results = []) => {
const visit = ({ item, children = [] }, res) => {
if (item) res.push(item);
children.forEach(child => visit(child, res));
}
visit({ children: tree }, results);
return results;
}
console.log(treeToList(tree));
.as-console-wrapper { top: 0; max-height: 100% !important; }
const flatten = (data) => data.map(({ children }) => ([...flatten(children)]));
Your current code does traverse the whole tree, but never actually extracts item from the data. Another issue is that you currently use map, which means the resulting value will always have the same amount of elements as the initial array. Use flatMap to increase or reduce the amount of elements in the array.
Changing your code as little as possible it might look like this:
const flatten = (data) => data.flatMap(({item, children}) => ([item, ...flatten(children)]));
const flatten = (data) => data.flatMap(({item, children}) => ([item, ...flatten(children)]));
const data = [{
item: {id: 1, name: "item name", code: "1d4g4"},
children: [{
item: {id: 2, name: "item name 2", code: "1d4g4"},
children: [{
item: {id: 2, name: "item name 2", code: "1d4g4"},
children: [{
item: {id: 3, name: "item name 2", code: "1d4g4"},
children:[
{item: {id: 4, name: "item name 2", code: "1d4g4"}, children: []},
{item: {id: 4, name: "item name 2", code: "1d4g4"}, children: []},
{item: {id: 4, name: "item name 2", code: "1d4g4"}, children: []},
]
}]
}]
}]
}];
console.log(flatten(data));
Could you help me plese? I need to compare and calculate the percentage of the difference between the values and return an array. I need to compare arrays, get to objects with name and value, and count the percentage. Suppose for the first item in array {name: 'Name 1', value: 1945}, go into the second item to find there {name: 'Name 1', value: 699}. The percentage for 1945 will be 100, for 699 - 36. I'm confused about nesting((
//input data
const data = [
{
_id: "0090908",
groups: [
{
_id: "24424",
name: "Group 1",
group_type: "group_1",
items: [
{ name: "Name 1", value: 1945 },
{ name: "Name 2", value: 0 },
{ name: "Name 3", value: 39 },
],
},
{
_id: "23030",
name: "Group 2",
group_type: "group_2",
items: [
{ name: "Name 4", value: 67 },
{ name: "Name 5", value: 123 },
{ name: "Name 6", value: 13 },
],
},
]
},
{
_id: "00390395",
groups: [
{
_id: "837583",
name: "Group 1",
group_type: "group_1",
items: [
{ name: "Name 1", value: 699 },
{ name: "Name 2", value: 55},
{ name: "Name 3", value: 39 },
],
},
{
_id: "8989305",
name: "Group 2",
group_type: "group_2",
items: [
{ name: "Name 4", value: 998 },
{ name: "Name 5", value: 12 },
{ name: "Name 6", value: 485 },
],
},
]
}
];
//result data
const result = [
{
_id: "0090908",
groups: [
{
_id: "24424",
name: "Group 1",
group_type: "group_1",
items: [
{ name: "Name 1", value: 1945, percent: 100, best: true },
{ name: "Name 2", value: 0, percent: 0, best: false },
{ name: "Name 3", value: 39, percent: 100, best: true },
],
},
{
_id: "23030",
name: "Group 2",
group_type: "group_2",
items: [
{ name: "Name 4", value: 67, percent: 6, best: false },
{ name: "Name 5", value: 123, percent: 100, best: true },
{ name: "Name 6", value: 13, percent: 3, best: true },
],
},
]
},
{
_id: "00390395",
groups: [
{
_id: "837583",
name: "Group 1",
group_type: "group_1",
items: [
{ name: "Name 1", value: 699, percent: 36, best: false },
{ name: "Name 2", value: 55, percent: 100, best: true},
{ name: "Name 3", value: 39, percent: 100, best: true },
],
},
{
_id: "8989305",
name: "Group 2",
group_type: "group_2",
items: [
{ name: "Name 4", value: 998, percent: 100, best: true },
{ name: "Name 5", value: 12, percent: 9, best: false },
{ name: "Name 6", value: 485, percent: 100, best: true },
],
},
]
}
];
First you need to run through all elements, finding the largest values of each name. Then you run again, placing the percentages.
var best = {}; // Our database of higher values
function checkLargest(data) {
if (!data) return;
// If is iterable perform the function on each element
if (Symbol.iterator in Object(data)) for (var el of data) checkLargest(el);
if (data.name && data.value !== undefined)
if (!best[data.name] || best[data.name] < data.value)
best[data.name] = data.value;
checkLargest(data.groups); // If doesn't exist will return
checkLargest(data.items);
}
function placePercentages(data) {
if (!data) return;
if (Symbol.iterator in Object(data)) for (var el of data) placePercentages(el);
if (data.name && data.value !== undefined) {
var higher = best[data.name];
data.percent = Math.round(data.value / higher * 100);
data.best = (higher == data.value);
}
placePercentages(data.groups);
placePercentages(data.items);
}
const d = [
{
_id: "0090908",
groups: [
{
_id: "24424",
name: "Group 1",
group_type: "group_1",
items: [
{ name: "Name 1", value: 1945 },
{ name: "Name 2", value: 0 },
{ name: "Name 3", value: 39 },
],
},
{
_id: "23030",
name: "Group 2",
group_type: "group_2",
items: [
{ name: "Name 4", value: 67 },
{ name: "Name 5", value: 123 },
{ name: "Name 6", value: 13 },
],
},
]
},
{
_id: "00390395",
groups: [
{
_id: "837583",
name: "Group 1",
group_type: "group_1",
items: [
{ name: "Name 1", value: 699 },
{ name: "Name 2", value: 55},
{ name: "Name 3", value: 39 },
],
},
{
_id: "8989305",
name: "Group 2",
group_type: "group_2",
items: [
{ name: "Name 4", value: 998 },
{ name: "Name 5", value: 12 },
{ name: "Name 6", value: 485 },
],
},
]
}
];
checkLargest(d);
placePercentages(d);
console.log(d);
I need a typescript function to recursively get the full path (parent hierarchy) of a given node by passing its value.
Let's say I have an array of objects like this:
items = [{
value: 2,
text: "Name 2",
children: [{
value: 7,
text: "Name 7",
children: [{
value: 10,
text: "Name 10",
children: []
},
{
value: 11,
text: "Name 11",
children: []
},
{
value: 12,
text: "Name 12",
children: [{
value: 13,
text: "Name 13",
children: [{
value: 14,
text: "Name 14",
children: []
},
{
value: 15,
text: "Name 15",
children: []
}
]
}]
}
]
}]
},
{
value: 16,
text: "Name 16",
children: [{
value: 17,
text: "Name 17",
children: [{
value: 18,
text: "Name 18",
children: []
},
{
value: 19,
text: "Name 19",
children: []
}
]
}]
}
];
Let's say I want to get the full path of node with value=19 by calling a function.
getPath(items, 19);
The expected result could be either returning only values of parent nodes
[16, 17, 19]
or array of objects as bellow:
[{
value: 16,
text: "Name 16"
},
{
value: 17,
text: "Name 17"
},
{
value: 19,
text: "Name 19"
}
]
Thanks,
Hope this help
const items = [{
value: 2,
text: "Name 2",
children: [{
value: 7,
text: "Name 7",
children: [{
value: 10,
text: "Name 10",
children: []
},
{
value: 11,
text: "Name 11",
children: []
},
{
value: 12,
text: "Name 12",
children: [{
value: 13,
text: "Name 13",
children: [{
value: 14,
text: "Name 14",
children: []
},
{
value: 15,
text: "Name 15",
children: []
}
]
}]
}
]
}]
},
{
value: 16,
text: "Name 16",
children: [{
value: 17,
text: "Name 17",
children: [{
value: 18,
text: "Name 18",
children: []
},
{
value: 19,
text: "Name 19",
children: []
}
]
}]
}
];
function getPath(items, val) {
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.value !== val) {
if (item.children) {
const path = getPath(item.children, val);
if (path) {
path.unshift(item.value);
return path;
}
}
} else {
return [item.value];
}
}
}
console.log(getPath(items, 19));
Here's the link for it