Related
I have an array of nested objects. I need to update the id property of each node by concatenating all its parent names.
id should be value of the name property of current node joined with name property
od it's parents separated by '/'
treeData = [{
name: 'Infiniti',
id: '',
children: [{
name: 'G50',
id: '',
children: [{
name: 'Pure AWD',
id: ''
},
{
name: 'Luxe',
id: ''
},
],
},
{
name: 'QX50',
id: '',
children: [{
name: 'Pure AWD',
id: ''
},
{
name: 'Luxe',
id: ''
},
],
},
],
},
{
name: 'BMW',
id: '',
children: [{
name: '2 Series',
id: '',
children: [{
name: 'Coupé',
id: ''
},
{
name: 'Gran Coupé',
id: ''
},
],
},
{
name: '3 Series',
id: '',
children: [{
name: 'Sedan',
id: ''
},
{
name: 'PHEV',
id: ''
},
],
},
],
},
];
Expected Outcome
[{
name: 'Infiniti',
id: 'Infiniti',
children: [{
name: 'G50',
id: 'Infiniti/G50',
children: [{
name: 'Pure AWD',
id: 'Infiniti/G50/Pure AWD'
},
{
name: 'Luxe',
id: 'Infiniti/G50/Luxe'
},
],
},
{
name: 'QX50',
id: 'Infiniti/QX50',
children: [{
name: 'Pure AWD',
id: 'Infiniti/QX50/Pure AWD'
},
{
name: 'Luxe',
id: 'Infiniti/QX50/Luxe'
},
],
},
],
},
{
name: 'BMW',
id: 'BMW',
children: [{
name: '2 Series',
id: 'BMW/2 Series',
children: [{
name: 'Coupé',
id: 'BMW/2 Series/Coupé'
},
{
name: 'Gran Coupé',
id: 'BMW/2 Series/Gran Coupé'
},
],
},
{
name: '3 Series',
id: 'BMW/3 Series',
children: [{
name: 'Sedan',
id: 'BMW/3 Series/Sedan'
},
{
name: 'PHEV',
id: 'BMW/3 Series/PHEV'
},
],
},
],
},
];
I tried to use Array.prototype.reduce(), but I am unable to get the previous value to concatinate.
function updateTreeData(array) {
return array.reduce((returnValue, currentValue) => {
if (currentValue.children != null) {
returnValue.push(Object.assign({}, currentValue, {
children: this.updateTreeData(currentValue.children)
}))
}
return returnValue
}, []);
}
console.log(updateTreeData(treeData))
You can try the recursion approach
const treeData=[{name:"Infiniti",id:"",children:[{name:"G50",id:"",children:[{name:"Pure AWD",id:""},{name:"Luxe",id:""}]},{name:"QX50",id:"",children:[{name:"Pure AWD",id:""},{name:"Luxe",id:""}]}]},{name:"BMW",id:"",children:[{name:"2 Series",id:"",children:[{name:"Coupé",id:""},{name:"Gran Coupé",id:""}]},{name:"3 Series",id:"",children:[{name:"Sedan",id:""},{name:"PHEV",id:""}]}]}];
const populateId = (list, currentId) => {
for(const item of list) {
if(!currentId) {
item.id = item.name
} else {
item.id = currentId + '/' + item.name
}
if(item.children) {
populateId(item.children, item.id)
}
}
}
populateId(treeData)
console.log(treeData)
I'm currently working on an inventorying app and I am trying to display the boxID and the amount of items inside of that box on a baseCard component that I have made.
The computed property that I made boxCards needs to spit the data out in this format
[{title: '', amount: null}] so it can be pushed onto each baseCard element.
Presently my computed property is giving me the title, but I cannot figure out how to get the amount of items inside of each box.
boxesInLocation returns this array: ["", "Box 1", "Box 4", "Box 4"]
Which is great, but now I need to count how many times each box shows up in that area and then push it to the reshapedItems function in the amount: spot.
Is this just a simple reduce method that I need to use? Because I've only be able to actually produce a number when calculating the length of the array.
Also, just reducing the array won't spit out the number to each individual instance of reshapedItem
Any ideas on what I can do here?
Cheers!
App.Vue Data:
data(){
userData: {
items: [
{
itemName: 'test book',
category: 'Books',
box: 'Box 3',
location: 'Kitchen',
},
{
itemName: 'test book 2',
category: 'Books',
box: 'Box 3',
location: 'Kitchen',
},
{
itemName: 'test book 3',
category: 'Books',
box: '',
location: 'Basement',
},
{
itemName: 'test record',
category: 'Records',
box: 'Box 1',
location: 'Basement',
},
{
itemName: 'test record 2',
category: 'Records',
box: 'Box 4',
location: 'Basement',
},
{
itemName: 'test furniture',
category: 'Furniture',
box: 'Box 2',
location: 'Garage',
},
{
itemName: 'test movie 1',
category: 'Movies',
box: 'Box 2',
location: 'Garage',
},
{
itemName: 'test movie 2',
category: 'Movies',
box: 'Box 2',
location: 'Garage',
},
{
itemName: 'test movie 3',
category: 'Movies',
box: 'Box 2',
location: 'Garage',
},
{
itemName: 'test Comicbook',
category: 'Movies',
box: 'Box 4',
location: 'Basement',
},
],
boxes: [
{ name: 'Box 1', location: 'Basement' },
{ name: 'Box 2', location: 'Garage' },
{ name: 'Box 3', location: 'Kitchen' },
{ name: 'Box 4', location: 'Basement' },
],
}
Page Component
data() {
return {
items: this.userData.items,
boxes: this.userData.boxes,
}
},
computed: {
boxCards() {
const filteredItems = this.items.filter((item) => item.location === 'Basement')
const itemsInBoxes = filteredItems.map((filteredItem) => {
return filteredItem.box
})
const filteredBoxes = this.boxes.filter((box) => box.location === 'Basement')
const reshapedBoxes = filteredBoxes.map((filteredBox) => {
return { boxID: `${filteredBox.name}`, amount: 100 }
})
return reshapedBoxes
},
You can count the items in the this.items array that have the same box name as the box in question:
return this.boxes
.filter((box) => box.location === 'Basement')
.map((box) => ({
boxId: `${box.name}`,
amount: this.items.filter(item => item.box === box.name).length
}));
You need to save the number of occurrences of each box in a Map, then, get the amount of each one in the second loop you're doing:
const userData = {
items: [
{ itemName: 'test book', category: 'Books', box: 'Box 3', location: 'Kitchen' },
{ itemName: 'test book 2', category: 'Books', box: 'Box 3', location: 'Kitchen' },
{ itemName: 'test book 3', category: 'Books', box: '', location: 'Basement' },
{ itemName: 'test record', category: 'Records', box: 'Box 1', location: 'Basement' },
{ itemName: 'test record 2', category: 'Records', box: 'Box 4', location: 'Basement' },
{ itemName: 'test furniture', category: 'Furniture', box: 'Box 2', location: 'Garage' },
{ itemName: 'test movie 1', category: 'Movies', box: 'Box 2', location: 'Garage' },
{ itemName: 'test movie 2', category: 'Movies', box: 'Box 2', location: 'Garage' },
{ itemName: 'test movie 3', category: 'Movies', box: 'Box 2', location: 'Garage' },
{ itemName: 'test Comicbook', category: 'Movies', box: 'Box 4', location: 'Basement' },
],
boxes: [
{ name: 'Box 1', location: 'Basement' },
{ name: 'Box 2', location: 'Garage' },
{ name: 'Box 3', location: 'Kitchen' },
{ name: 'Box 4', location: 'Basement' },
]
};
function boxCards() {
const boxesCount = userData.items
.reduce((quantity, {box}) =>
quantity.set(box, 1 + (quantity.get(box) || 0))
, new Map);
return userData.boxes
.filter(box =>
box.location === 'Basement'
)
.map(filteredBox =>
({ boxID: filteredBox.name, amount: boxesCount.get(filteredBox.name) })
);
}
console.log( boxCards() );
Hello everyone and dear friends. While learning React, I noticed that I lacked javascript and I started to learn javascript carefully.
Let me try to tell you what I am trying to do. I have two arrays. I want to move one of the elements of the instance element in array1 to the instance in array2.
How can I do it? Which method would you recommend? Does it work to splice the element and push it down? How can a function be written for this? I would be glad if you help.
const array1 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },
{ id: '36', title: 'Example 3' }, // delete this object from here
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' }
],
},
];
I want to move the element I deleted into this array.
const array2 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' },
// { id: '36', title: 'Example 3' }, // i want to move here
],
},
];
You can use pop() to remove last element from array.
const array1 = [{
id: '1',
instance: [{
id: '34',
title: 'Example 1'
},
{
id: '35',
title: 'Example 2'
},
{
id: '36',
title: 'Example 3'
}
],
}, {
id: '2',
instance: [{
id: '37',
title: 'Example 4'
}],
}, ];
let tmp = array1[0].instance[2];
array1[0].instance.pop();
array1[1].instance.push(tmp);
console.log(array1);
const array1 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },
{ id: '36', title: 'Example 3' }, // delete this object from here
]
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' }
]
}
];
const array2 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },
]
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' },
// { id: '36', title: 'Example 3' }, // i want to move here
]
}
];
//answer
function transfer(fromArr,index,toArr){
toArr.push(fromArr.splice(index,1))
}
transfer(array1[0].instance,2,array2[1].instance)
console.log("first array",array1)
console.log("second array",array2)
const array1 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },
{ id: '36', title: 'Example 3' },] // delete this object from here
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' }
],
},
];
var temp = array1[0]
array1.splice(0,1);
const array2 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },]
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' },
// { id: '36', title: 'Example 3' }, // i want to move here
],
},
];
array2.push(temp)
console.log(array2)
First thing, your object has wrong brackets. Here is a fixed version for array1
const array1 = [
{
id: '1',
instance: [
{ id: '34', title: 'Example 1' },
{ id: '35', title: 'Example 2' },
{ id: '36', title: 'Example 3' }, // delete this object from here
]
},
{
id: '2',
instance: [
{ id: '37', title: 'Example 4' }
],
},
];
Now remove one element, IDK how you're getting the key for this, so I ill just declare it as constant, up to you to modify
let key = 0;
let Nested_key = 2;
let removed = array1[key].instance.splice(Nested_key,1) //1st param= 0: the position, 2nd param = 1 number of elements to rm starting from param1 position
Now we removed the element, and it is stored in removed (an array of length=1), just insert it now
array2[key].instance.push(removed[0]);
Judging by your post, it Seems like you knew already what splice and push are and what they do (the name are quite clear and intuitive). Feel free to ask for clarifications if there is any part that you don't understand in my answer
So I have the following Array. I can push to the parent level and child level however I can't seem to push to Children of Children or deeper. Here's the Array:
TREE_DATA: SegmentCategory[] = [
{
id: 1,
name: 'Category 1',
children: [
{
id: 2,
name: 'Category 1-1',
children: [
{
id: 4,
name: 'Category 1-1-a',
children: []
},
{
id: 5,
name: 'Category 1-1-b',
children: []
},
]
},
{
id: 6,
name: 'Category 1-2',
children: [
{
id: 7,
name: 'Category 1-2-a',
children: [
{
id: 8,
name: 'Category 1-2-1',
children: [
{
id: 9,
name: 'Category 1-2-2-a',
children: []
}
]
}
]
}
]
}
]
},
{
id: 10,
name: 'Category 2',
children: []
}
];
And here is the method I am using to add data to the array:
createCategory() {
this.id++;
if (this.formGroup.controls['parentCategory'].value == null) {
this.TREE_DATA.push(
{
id: this.id,
name: this.formGroup.controls['categoryName'].value,
children: []
});
} else {
this.TREE_DATA.forEach((v, index) => {
if (v.id === this.formGroup.controls['parentCategory'].value.id) {
this.TREE_DATA[index].children.push(
{
id: this.id,
name: this.formGroup.controls['categoryName'].value,
children: []
}
);
}
});
}
}
I know that I can just add an additional foreach however this doesn't seem like the best way to handle this, as I could want to go 5-6 layers down at any time to add a new nested child. What would be the best way to handle this?
You could take a recursive function for finding an object in the tree.
function find(array, id) {
var result;
array.some(object => {
if (object.id === id) return result = object;
return result = find(object.children || [], id);
});
return result;
}
var data = [{ id: 1, name: 'Category 1', children: [{ id: 2, name: 'Category 1-1', children: [{ id: 4, name: 'Category 1-1-a', children: [] }, { id: 5, name: 'Category 1-1-b', children: [] }] }, { id: 6, name: 'Category 1-2', children: [{ id: 7, name: 'Category 1-2-a', children: [{ id: 8, name: 'Category 1-2-1', children: [{ id: 9, name: 'Category 1-2-2-a', children: [] }] }] }] }] }, { id: 10, name: 'Category 2', children: [] }];
console.log(find(data, 9));
console.log(find(data, 'unknown'));
I would like to group all messages between 2 people in a group (chat). Doesn`t matter if I am the author or receiver.
Let's say this example code.
const messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]
Imagine, I am user ID = 1, so I would like to get this:
const chats = [
{
chatName: 'Name of user ID 2', messages: [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
]
},
{
chatName: 'Name of user ID 3', messages: [
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]
}
];
How can I achieve this with Lodash?
Not sure about lodash, but you can use plain js - reduce and map to get that structure
const messages = [{
id: '100',
text: 'aaa',
author: {
id: '1'
},
receiver: {
id: '2'
}
},
{
id: '101',
text: 'bbb',
author: {
id: '2'
},
receiver: {
id: '1'
}
},
{
id: '102',
text: 'ccc',
author: {
id: '3'
},
receiver: {
id: '1'
}
},
];
function groupByPair(arr) {
return [
...arr.reduce((a, b) => {
let {
author,
receiver
} = b;
let s = [author.id, receiver.id].sort().join('-');
a.set(s, a.has(s) ? a.get(s).concat(b) : [b]);
return a;
}, new Map)
].map(e => ({
chatName: 'Name of user ID ' + e[0].substring(e[0].indexOf('-') + 1),
messages: e[1]
}));
}
console.log(groupByPair(messages));
Using either Lodash or Underscore.js:
var grouped = _.groupBy(messages, m => _.sortBy([m.author.id, m.receiver.id]));
var formatted = _.map(grouped, (v, name) => ({ chatname: name, messages: v }));
You could combine those into a single line, but that seems overly dense to my eyes.
I took the liberty of defining a more complex test dataset, to make sure the edge cases were better covered:
var messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
{ id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } },
{ id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } },
{ id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
]
With this data, the code above yields a formatted of:
[
{ chatname: '1,2',
messages: [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } }
]
},
{ chatname: '1,3', messages: [
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
{ id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
]
},
{ chatname: '3,4', messages: [
{ id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } }
]
}
]
The major difference with your desired output relates to the chatname values. I did not see how you were naming those, so I stuck with Lodash/Underscore's native groupby keys.
You can do this with _.groupby. I filter the array first so that you're only left with messages that involve user 1.
const messages = [
{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
{ id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
{ id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
];
const filtered = messages.filter((msg) => {
return msg.author.id === '1' || msg.receiver.id === '1'
});
const groups = _.groupBy(filtered, (msg) => {
return msg.author.id === '1' ? msg.receiver.id : msg.author.id
});
console.log(groups);
<script src="https://unpkg.com/lodash#4.17.4"></script>