How to remove items in deep array of objects? - javascript

Suppose I have the following array of objects:
[
{ id: "1", categories: [ { category_id: "1"}, { category_id: "2"} ],
{ id: "2", categories: [ { category_id: "2"}, { category_id: "3"} ],
{ id: "3", categories: [ { category_id: "1"}, { category_id: "5"} ],
]
I want remove all the items which doesn't have as category_id those not included in this array of references: 1, 4, 5.
So the expected output should be: 1, 3, because the id 2 doesn't have any category id contained in teh references array.
I wrote this code:
items.filter(obj => !references.includes(obj.categories.category_id));
but this will return the same items
Expected result:
[
{ id: "1", categories: [ { category_id: "1"}, { category_id: "2"} ],
{ id: "3", categories: [ { category_id: "1"}, { category_id: "5"} ],
]

You could use Array#filter, Array#some and the value with Array#includes.
var array = [{ id: "1", categories: [{ category_id: "1" }, { category_id: "2" }] }, { id: "2", categories: [{ category_id: "2" }, { category_id: "3" }] }, { id: "3", categories: [{ category_id: "1" }, { category_id: "5" }] }],
keep = ["1", "4", "5"],
result = array.filter(({ categories }) =>
categories.some(({ category_id }) => keep.includes(category_id)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

obj.categories is an array, you have to iterate it in some way:
items.filter(obj => obj.categories.every(category => !references.includes(category.category_id)));

Here you have another approach that uses Array::findIndex()
const input = [
{id: "1", categories: [{category_id: "1"}, {category_id: "2"}]},
{id: "2", categories: [{category_id: "2"}, {category_id: "3"}]},
{id: "3", categories: [{category_id: "1"}, {category_id: "5"}]},
];
const references = [1, 4, 5];
let res = input.filter(
y => y.categories.findIndex(x => references.includes(Number(x.category_id))) >= 0
);
console.log(res);

Related

Group nested object using lodash

I have object like this.
data = [
{
id: "0",
name: "maths",
levelNo: 0,
level: null
},
{
id: "15",
name: "sceince",
levelNo: 0,
level: null
},
{
name: "algebra",
id: "1",
parentId: "0",
levelNo: 1,
level: {
id: "0",
name: "maths"
}
},
{
name: "alfunction",
id: "2",
parentId: "1",
levelNo: 2,
level: {
id: "1",
name: "alegera"
}
},
{
name: "bhumiti",
id: "3",
parentId: "1",
levelNo: 2,
level: {
id: "1",
name: "alegera"
}
},
{
name: "paryavan",
id: "4",
parentId: "0",
levelNo: 1,
level: {
id: "0",
name: "maths"
}
},
{
name: "trikon",
id: "5",
parentId: "3",
levelNo: 3,
level: {
id: "3",
name: "bhumiti"
}
}];
and convert this object into
subject = [
{
name: "maths",
id: "0",
items: [
{
id: "1",
name: "alegera",
items: [
{
name: "alfunction",
id: "2"
},
{
name: "bhumiti",
id: "3",
items: [
{
name: "trikon",
id: "5"
}
]
}
]
},
{
id: "4",
name: "paryavan"
}
]
}];
You could take a function which uses parentId and id without levelNo and level.
const
getTree = (data, root) => {
const t = {};
data.forEach(({ parentId, levelNo, level, ...o }) =>
((t[parentId] ??= {}).children ??= []).push(Object.assign(t[o.id] ??= {}, o))
);
return t[root].children;
},
data = [{ id: "0", name: "maths", levelNo: 0, level: null }, { id: "15", name: "sceince", levelNo: 0, level: null }, { name: "algebra", id: "1", parentId: "0", levelNo: 1, level: { id: "0", name: "maths" } }, { name: "alfunction", id: "2", parentId: "1", levelNo: 2, level: { id: "1", name: "alegera" } }, { name: "bhumiti", id: "3", parentId: "1", levelNo: 2, level: { id: "1", name: "alegera" } }, { name: "paryavan", id: "4", parentId: "0", levelNo: 1, level: { id: "0", name: "maths" } }, { name: "trikon", id: "5", parentId: "3", levelNo: 3, level: { id: "3", name: "bhumiti" } }],
tree = getTree(data);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comparing 2 arrays and fetch values to see if array 1 is greater than array 2

I am still in the midst of learning React and Javascript and have came to a roadblock with my current project.
Project goal
I am trying to map through two array of objects, and check if a certain property matches.
if recommendedSkillTree.skills.skill === currentSkills.skill, I would then like to check if recommendedSkillTree.skills.level > currentSkills.level.
if the above condition matches, or if currentSkills.skill do not have the skills in the recommendedSkillTree Data, the skill will then show up in a red text. Else, green text.
What I have done
I have tried mapping between the 2 arrays to check if currentSkills.skill === recommendedSkillTree.skills.skill.
const skillMatch = recommendedSkillTree.filter((skillRecommended) =>
currentSkills.some((skillCurrent) => skillRecommended.skills.skill === skillCurrent.skill)
);
.
.
.
return (
<div>
{recommendedSkillTree.map((item, i) => (
<div key={item.id}>
<div
style={{
color: !skillMatch[i] ? "red" : "green",
}}
>
{item.skill}
</div>
</div>
))}
</div>
By doing so, I am able to churn out an output where skills that are present in currentSkills are shown in green, and those that are not in it are shown in red.
Next I would like to go one step deeper, and tried to compare the skill level of the present skills, and if they fall short of the recommended level, the text would then show in red.
const levelGap = recommendedSkillTree.map((recommendedLevel) =>
currentSkills.some((levelCurrent) => recommendedLevel.level > levelCurrent.level)
);
By doing so, I would be expecting an output of
[true, false, true, true, true, true, true, true, true]
instead I've got:
[true, true, true, true, false, true, true, false, false]
I am unable to see which part have went wrong. Would greatly appreciate if any seniors in this field would guide me along.
Data 1
const recommendedSkillTree = [
{
id: "1",
role: "Paladin",
skills: [
{
id: "1",
skill: "Attack",
level: "3",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "3",
},
{
id: "4",
skill: "Heal",
level: "4",
},
{
id: "5",
skill: "Group Heal",
level: "2",
},
{
id: "6",
skill: "Double Attack",
level: "4",
},
{
id: "7",
skill: "Ultimate",
level: "3",
},
{
id: "8",
skill: "Defense Up",
level: "2",
},
{
id: "9",
skill: "Attack Up",
level: "2",
},
],
},
];
export default recommendedSkillTree;
Data 2
const currentSkills = [
{
id: "1",
skill: "Attack",
level: "2",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "2",
},
{
id: "4",
skill: "Heal",
level: "3",
},
{
id: "5",
skill: "Final Slash",
level: "3",
},
];
export default currentSkills;
Thank you in advance for your time, and I do apologize if my way of asking questions are not up to community standard as this is my first time posting on here.
I do not really have anyone around me to ask questions on since I am fully self-taught and no one around me is in the tech field. Thank you so much.
This may be one possible solution to achieve the desired objective.
Code Snippet
const isGreenOrRed = (reco, curr) => (
reco.skills.map(re => (
curr.some(({skill}) => skill === re.skill)
? curr.find(({skill}) => skill === re.skill)['level'] >= re.level
? 'green'
: 'red'
: 'red'
))
);
const recommendedSkillTree = [
{
id: "1",
role: "Paladin",
skills: [
{
id: "1",
skill: "Attack",
level: "3",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "3",
},
{
id: "4",
skill: "Heal",
level: "4",
},
{
id: "5",
skill: "Group Heal",
level: "2",
},
{
id: "6",
skill: "Double Attack",
level: "4",
},
{
id: "7",
skill: "Ultimate",
level: "3",
},
{
id: "8",
skill: "Defense Up",
level: "2",
},
{
id: "9",
skill: "Attack Up",
level: "2",
},
],
},
];
const currentSkills = [
{
id: "1",
skill: "Attack",
level: "2",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "2",
},
{
id: "4",
skill: "Heal",
level: "3",
},
{
id: "5",
skill: "Final Slash",
level: "3",
},
];
console.log(isGreenOrRed(recommendedSkillTree[0], currentSkills).join(", "));
const SomeComp = ({getColor, ...props}) => (
<div>
{recommendedSkillTree[0].skills.map((item, i) => (
<div key={item.id}>
<div
style={{
color: getColor[i]
}}
>
{item.skill}
</div>
</div>
))}
</div>
);
ReactDOM.render(
<div>
<h4>Demo UI</h4>
<SomeComp getColor={isGreenOrRed(recommendedSkillTree[0], currentSkills)}/>
</div>,
document.getElementById('rd')
);
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
this uses the same logic as attempted by OP in the question
fixes some of the issues faced
Below solution employs an alternative approach to get the same result.
Code Snippet
const isGreenOrRed = (needle, haystack) => (
haystack.some(({skill}) => skill === needle.skill)
? haystack.find(({skill}) => skill === needle.skill)['level'] >= needle.level
? 'green'
: 'red'
: 'red'
);
const recommendedSkillTree = [
{
id: "1",
role: "Paladin",
skills: [
{
id: "1",
skill: "Attack",
level: "3",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "3",
},
{
id: "4",
skill: "Heal",
level: "4",
},
{
id: "5",
skill: "Group Heal",
level: "2",
},
{
id: "6",
skill: "Double Attack",
level: "4",
},
{
id: "7",
skill: "Ultimate",
level: "3",
},
{
id: "8",
skill: "Defense Up",
level: "2",
},
{
id: "9",
skill: "Attack Up",
level: "2",
},
],
},
];
const currentSkills = [
{
id: "1",
skill: "Attack",
level: "2",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "2",
},
{
id: "4",
skill: "Heal",
level: "3",
},
{
id: "5",
skill: "Final Slash",
level: "3",
},
];
console.log(recommendedSkillTree[0].skills.map(it => isGreenOrRed(it, currentSkills)).join(", "));
const SomeComp = () => (
<div>
{recommendedSkillTree[0].skills.map(item => (
<div key={item.id}>
<div
style={{
color: isGreenOrRed(item, currentSkills)
}}
>
{item.skill}
</div>
</div>
))}
</div>
);
ReactDOM.render(
<div>
<h4>Demo UI - Alternate Approach</h4>
<SomeComp />
</div>,
document.getElementById('rd')
);
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
This pushes the validation at the individual skill object level
Thus, re-using the existing .map iteration happening in the JSX
Here's an example using Lodash map. You can try play around with the check function to get the desired result.
const recommendedSkillTree = [{
id: "1",
role: "Paladin",
skills: [{
id: "1",
skill: "Attack",
level: "3",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "3",
},
{
id: "4",
skill: "Heal",
level: "4",
},
{
id: "5",
skill: "Group Heal",
level: "2",
},
{
id: "6",
skill: "Double Attack",
level: "4",
},
{
id: "7",
skill: "Ultimate",
level: "3",
},
{
id: "8",
skill: "Defense Up",
level: "2",
},
{
id: "9",
skill: "Attack Up",
level: "2",
},
],
}];
const currentSkills = [{
id: "1",
skill: "Attack",
level: "2",
},
{
id: "2",
skill: "Block",
level: "3",
},
{
id: "3",
skill: "Taunt",
level: "2",
},
{
id: "4",
skill: "Heal",
level: "3",
},
{
id: "5",
skill: "Final Slash",
level: "3",
},
];
var result = [];
function check(skill) {
var found = _.find(currentSkills, function(o) {
return o.skill === skill.skill;
});
if (found) {
result.push(found.level >= skill.level);
} else {
result.push(false);
}
}
_.map(recommendedSkillTree[0].skills, check);
console.log(result);
<script src="https://lodash.com/vendor/cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>

GroupBy array and then sortBy date that array using lodash

I have an array like so:
[
{id: "1", description: "Insurance", date: "2020-12-22T00:00:00Z"},
{id: "2", description: "Salary", date: "2020-12-20T00:00:00Z"},
{id: "3", description: "Interest", date: "2020-12-20T00:00:00Z"},
{id: "4", description: "Panera", date: "2020-12-19T00:00:00Z"},
{id: "5", description: "Citibank", date: "2020-12-18T00:00:00Z"},
]
Now I want GroupBy date, then sortBy date newest, here is my code, I'm using lodash
const groups = _(list)
.groupBy((trans) => moment(trans.date).format('MM/DD/YYYY'))
.sortBy(group => list.indexOf(group[0]))
.value();
The array result of code above like:
[
0: [
{id: "1", description: "Insurance", date: "2020-12-22T00:00:00Z"}
],
1: [
{id: "2", description: "Salary", date: "2020-12-20T00:00:00Z"},
{id: "3", description: "Interest", date: "2020-12-20T00:00:00Z"}
],
2: [
{id: "4", description: "Panera", date: "2020-12-19T00:00:00Z"}
]
3: [
{id: "5", description: "Citibank", date: "2020-12-18T00:00:00Z"}
]
]
But I would like the array to return like below:
[
{
date: 12/22/2020,
items: [
{id: "1", description: "Insurance", date: "2020-12-22T00:00:00Z"}
]
},
{
date: 12/20/2020,
items: [
{id: "2", description: "Salary", date: "2020-12-20T00:00:00Z"},
{id: "3", description: "Interest", date: "2020-12-20T00:00:00Z"}
],
},
{
date: 12/19/2020,
items: [
{id: "4", description: "Panera", date: "2020-12-19T00:00:00Z"}
]
},
{
date: 12/18/2020,
items: [
{id: "5", description: "Citibank", date: "2020-12-18T00:00:00Z"}
]
}
]
How I can do this with lodash.
Thank for your answer.
If vanilla JS solution works for you, you can make use of Array.prototype.reduce() to group your objects and Array.prototype.sort() to sort the output:
const src = [
{id: "5", description: "Citibank", date: "2020-12-18T00:00:00Z"},
{id: "1", description: "Insurance", date: "2020-12-22T00:00:00Z"},
{id: "2", description: "Salary", date: "2020-12-20T00:00:00Z"},
{id: "3", description: "Interest", date: "2020-12-20T00:00:00Z"},
{id: "4", description: "Panera", date: "2020-12-19T00:00:00Z"},
],
result = [...src
.reduce((acc,o) => {
const [yyyy, mm, dd] = o.date.split(/[\-T]/),
key = [mm, dd, yyyy].join('/'),
group = acc.get(key)
group
? group.items.push(o)
: acc.set(key, {date: key, items: [o]})
return acc
}, new Map)
.values()]
.sort(({date:a},{date:b}) => b.localeCompare(a))
console.log(result)
.as-console-wrapper{min-height:100%;}

tree recursive with cartesian implementation

I need help to find all combined possibilities from a tree
I readed a lot of documentation about cartesian product, tried a lot of things but none of them seems to work properly...
This is my tree
var data = [
{
"id": 5,
"name": "Support papier",
"type": "filter",
"children": [
{
"id": 24,
"name": "60 g/m² papier mat",
"type": "value",
"children": []
},
{
"id": 7,
"name": "90 g/m² papier couché",
"type": "value",
"children": [
{
"id": 8,
"name": "Propriété papier",
"type": "filter",
"children": [
{
"id": 18,
"name": "Papier mat",
"type": "value",
"children": [],
},
{
"id": 60,
"name": "Papier brillant",
"type": "value",
"children": [],
}
]
}
],
}
]
}
]
And this is my expected result :
[
[
{id: 5, name:"support papier", type: "filter"},
{id: 24, name:"60 g/m² papier mat", type: "value"},
],
[
{id: 5, name:"support papier", type: "filter"},
{id: 7, name:"90 g/m² papier mat", type: "value"},
{id: 8, name:"Propriété papier", type: "filter"},
{id: 18, name:"Papier mat", type: "value"},
],
[
{id: 5, name:"support papier", type: "filter"},
{id: 7, name:"90 g/m² papier mat", type: "value"},
{id: 8, name:"Propriété papier", type: "filter"},
{id: 60, name:"Papier brillant", type: "value"},
]
]
Of course, every empty array can be populated... :)
Thx for your help :)
You could get each level and map the next lower level to the result set.
Now, what is it doing?
The first part of collecting data is just getting all nodes to the end of the children's objects.
The other part is using a cartesian product for children which object has
type === 'value'
This works in two steps
Collect all items by getting the data and map these items with the actual object.
Create a cartesian product from an array of items.
The rest is just either pushing a new array with parts and adding the actual object (without children) or if no children are available, only the actual object in an array.
function getData(array) {
return array.reduce((r, { children, ...o }) => {
if (children.length) {
var parts = o.type === 'value'
? children
.map(({ children = [], ...p }) => getData(children).map(q => [p, ...q]))
.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []))
: getData(children);
r.push(...parts.map(q => [o, ...q]));
} else {
r.push([o]);
}
return r;
}, []);
}
var data = [{ id: 5, name: "Support papier", type: "filter", children: [{ id: 24, name: "60 g/m² papier mat", type: "value", children: [{ id: 9, name: "Finition", type: "filter", children: [{ id: 19, name: "Sans finition", type: "value", children: [] }, { id: 20, name: "Vernis anti UV", type: "value", children: [] }] }, { id: 8, name: "Propriété papier", type: "filter", children: [{ id: 60, name: "Papier brillant", type: "value", children: [] }, { id: 18, name: "Papier mat", type: "value", children: [] }] }] }, { id: 7, name: "90 g/m² papier couché", type: "value", children: [{ id: 8, name: "Propriété papier", type: "filter", children: [{ id: 18, name: "Papier mat", type: "value", children: [] }, { id: 60, name: "Papier brillant", type: "value", children: [] }] }] }] }],
result = getData(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Flatten nested json array using javascript

I have the following JSON array:
[
{ id: 1, name: "P1", groups: [ { id: 1.1, name: "G1.1" }, { id: 1.2, name:"G1.2" }]},
{ id: 2, name: "P2", groups: [ { id: 2.1, name: "G2.1" }, { id: 2.2, name:"G2.2" }]}
];
What is the most efficient method to convert it to the following structure using Javascript ES6?
[
{ id: 1, name: "P1", group_id: 1.1, group_name: "G1.1"},
{ id: 1, name: "P1", group_id: 1.2, group_name: "G1.2"},
{ id: 2, name: "P2", group_id: 1.1, group_name: "G2.1"},
{ id: 2, name: "P2", group_id: 1.1, group_name: "G2.2"},
]
There are some problems.
If it is a json array, it should be like this.
var obj = [{
"id": 1,
"name": "P1",
"groups": [{
"id": 1.1,
"name": "G1.1"
}, {
"id": 1.2,
"name": "G1.2"
}]
},
{
"id": 2,
"name": "P2",
"groups": [{
"id": 2.1,
"name": "G2.1"
}, {
"id": 2.2,
"name": "G2.2"
}]
}
];
you can validate json arrays using this link
it little bit confused about your out put.That's why it made voting down.
After set an array, you can use ForEach for that.
var obj = [{
"id": 1,
"name": "P1",
"groups": [{
"id": 1.1,
"name": "G1.1"
}, {
"id": 1.2,
"name": "G1.2"
}]
},
{
"id": 2,
"name": "P2",
"groups": [{
"id": 2.1,
"name": "G2.1"
}, {
"id": 2.2,
"name": "G2.2"
}]
}
];
res = [];
obj.forEach((e)=>{
e.groups.forEach((group)=>{
res.push({
"id" : e.id,
"name" : e.name,
"group_id" : group.id,
"group_name" : group.name
});
});
});
console.log(res);
You can achieve this using forEach.
Try the following:
var arr=[
{ id: 1, name: "P1", groups: [ { id: 1.1, name: "G1.1" }, { id: 1.2, name:"G1.2" }]},
{ id: 2, name: "P2", groups: [ { id: 2.1, name: "G2.1" }, { id: 2.2, name:"G2.2" }]}
];
result = [];
arr.forEach((o)=>{
o.groups.forEach((group)=>{
result.push({
"id" : o.id,
"name" : o.name,
"group_id" : group.id,
"group_name" : group.name
});
});
});
console.log(result);

Categories