react js useState update the quantity - javascript

I am new to react. I have got an issue updating a quantity.
const[persons,setPersons] = useState(personLists)
if you console.log(persons) it will give output as below. Now I want to
update qty for particular misc index of particular person index .
I have two persons in below array and each person have further two misc array
[
{
id: 1,
name: "john",
gender: "m",
misc: [
{
id: 1,
name: "xxx",
qty: 1
},
{
id: 2,
name: "xxx1",
qty: 1
}
]
},
{
id: 2,
name: "mary",
gender: "f",
misc: [
{
id: 1,
name: "aaa",
qty: 1
},
{
id: 2,
name: "bbb",
qty: 1
}
]
},
]
Now i want to update qty under misc array for that particular person.I have a function that takes the index of person array and index of misc array as below.
const updatePersonMiscQty = (personIndex, miscIndex) => {
setPersons(persons =>
persons.map((person,key) => {
const found = person.misc.find(d => key === miscIndex);
if (found) {
found.qty += 1;
}
return person;
})
}
let say my personIndex is 0 and miscIndex= is 1
so when usse click the button It should look into first person array, go to second index of misc and update qty.
I am looking for a solutions

access the items by indexes and update
setPersons(persons => {
const miscItem = persons[personIndex]?.misc?.[miscIndex]
if (miscItem ) {
miscItem.qty += 1;
}
return [...persons];
}
})

Related

Merge duplicated objects in javascript array with their appearance frequence

i have a javascript array who look like this
[
{ quantity: 1, name: 'Menu sandwichs' },
{ quantity: 1, name: 'Menu sandwichs' },
{ quantity: 1, name: 'Menu sandwichs' },
{ quantity: 1, name: 'Pizza' },
{ quantity: 1, name: 'Piza' }
]
and i want to get this array
[
{ quantity:3, name:'Menu Sandwich' },
{ quantity:2, name:'Pizza' }
]
Could you hel me please ?
Assuming the quantities in the original array may sometimes be something other than 1:
const mergeQuantities = (values) => {
const result = {}
values.forEach(({ quantity, name }) => {
result[name] = result[name] || { name, quantity: 0 }
result[name].quantity += quantity
})
return Object.values(result)
}
This creates a new object where the attribute names are the name from each thing in the array. Then iterates over the list, adding each quantity to the result. Finally, it discards the keys, leaving just the array in the form you want.

Filtering an array of objects Vue

I have an array of objects and Im trying to filter by matching ids
//Vehicle is added to quote
function filterByID(item) {
return item.id === 1;
}
this.vehicle = this.data.filter(filterByID);
data is as follows:
data: [
0: {
id: 0,
name: name
},
1: {
id: 1,
name: name
},
2: {
id: 2,
name: name
}
]
Im getting an empty error when I check the vehicle part
Are you using it like this:
const data = [
{
id: 0,
name: '',
},
{
id: 1,
name: '',
},
{
id: 2,
name: '',
},
];
function filterByID(item) {
return item.id === 1;
}
console.log(data.filter(filterByID)); // output: [{ "id": 1, "name": "" }]
You don't always need to define a separate function, you can use an arrow function, as below.
const data = [{
id: 0,
name: name
},
{
id: 1,
name: name
},
{
id: 2,
name: name
}
]
const vehicle = data.filter(item => item.id === 1);
console.log(vehicle);
This works fine in pure JS, it looks like it might be an issue with the lifecycle or state of your application. Use console.log to make sure that this.data is what you expect it to be

Most efficient way to sort a collection of arrays based off the order of a seperate array

Yes I am aware of similar questions but it doesn't quite cover my use case here.
I'm having trouble finding a way to bring the time complexity of this down
I have two objects like so
const people = [
{
name: 'Steve',
id: 1,
fruitInBasket: 6
},
{
name: 'James',
id: 2,
fruitInBasket: 4
}
]
const homes = [
{
id: 1,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
},
{
id: 2,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
}
]
so one is a collection of people with a count of fruit in a basket and the other is a collection of homes and within each home is the same users as in the people collection.
Now I want to order the users in each home based on the count of fruitInBasket so I have done this
// create an empty table to store the order of the people
let orderTable = {};
// order the people based off the count in fruitInBasket using lodash orderBy
people = orderBy(people, ['fruitInBasket'], ['desc']);
// create the table
orderTable = people.reduce((acc, item, index) => {
return {
...acc,
[item.id]: index
}
}, {});
// order the people in each home based on the order in the `orderTable`
homes.forEach((home) => {
let members = [];
home.familyMembers.forEach((member) => {
let i = orderTable[member.id];
members[i] = member;
});
home.familyMembers = members;
})
so immediately you can see a nested for loop - which is never ideal.. but I can't figure out a way around this. This method has to sort through quite a lot of data and I am noticing huge performance issues.
Any help would be appreciated!
This should be O(N log N). Its performance bottleneck is the one time sort. Everything else is just O(N) iteration. Some microoptimizations still possible.
Generate an ordered map lookup table.
Just move arrays based on that mapping.
There is a hpc sort library that is measured around 10-40x faster than built-in JavaScript on benchmarks that can be added to increase performance.
I'm not sure, but is the familyMember table the same for every home object? Can you not just copy the same familyMember array to every object or do they have different properties?
Extra optimization per home could be to convert above table to index to index mapping, so that native level array indexing will be used for subsequent ordering.
const orderMap = Object.fromEntries(people.sort((x,y)=>x.fruitInBasket-y.fruitInBasket).map(({id},i)=>[id,i]))
// O(N)+O(NlogN)
homes.forEach(home=>{
const {familyMembers:fms} = home
const arr = new Array(fms.length)
//may want to prefill to maintain PACKED array: https://v8.dev/blog/elements-kinds#avoid-creating-holes
for(const fm of fms) arr[ orderMap[fm.id] ] = fm
home.familyMembers = arr
})
// map lookup O(N)
console.log(homes)
<script>
const people = [
{
name: 'Steve',
id: 1,
fruitInBasket: 6
},
{
name: 'James',
id: 2,
fruitInBasket: 9
}
]
const homes = [
{
id: 1,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
},
{
id: 2,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
}
]
</script>
You can filter and sort:
const people = [
{
name: 'Steve',
id: 1,
fruitInBasket: 6
},
{
name: 'James',
id: 2,
fruitInBasket: 4
},
{
name: 'Cesar',
id: 3,
fruitInBasket: 14
}
]
const homes = [
{
id: 1,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Cesar',
id: 3
},
{
name: 'Steve',
id: 1
}
]
},
{
id: 2,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
}
]
homes.forEach(function(home){
home.familyMembers.sort((a,b)=>people.find(x=>x.id == a.id).fruitInBasket - people.find(x=>x.id == b.id).fruitInBasket)
})
console.log(homes)
Explanations:
You will iterate through homes:
homes.forEach(function(home){
You will sort the members:
.familyMembers.sort((a,b)
To sort, you have to get the fruits of the members, so you find the correct ID then take the correct property:
people.find(x=>x.id == a.id).fruitInBasket
Then you compare:
(a,b)=>people.find(x=>x.id == a.id).fruitInBasket - people.find(x=>x.id == b.id).fruitInBasket
If what you're looking for is performance, you should change people strucutre:
const people = {
1: {
name: 'Steve',
fruitInBasket: 6
},
2: {
name: 'James',
fruitInBasket: 4
}
}
This way you can retrieve fruits more easily:
people[id].fruits
Also, if your "id" is defined somewhere, don't define it in another place. Your homes should look like this:
const homes = {
1: {
familyMembers: [1, 2, 3]
},
2: {
familyMembers: [1,2]
}
}
So your algorithm goes like this:
const people = {
1: {
name: 'Steve',
fruitInBasket: 6
},
3: {
name: 'James',
fruitInBasket: 4
},
2: {
name: 'Cesar',
fruitInBasket: 9114
}
}
const homes = {
1: {
familyMembers: [1, 2, 3]
},
2: {
familyMembers: [1,2]
}
}
Object.keys(homes).forEach(function(k){
homes[k].familyMembers.sort((a,b)=>people[a].fruitInBasket - people[b].fruitInBasket)
})
console.log(homes)

Filter json with set and map using nested attributes

I am working with some json returned via an API call and trying to figure if it's possible to filter one json object based on the values from another. I came across set and map which is close, but not sure how to handled the nested attributed... here is a simplified example:
var teachers = [
{id: 1, name : 'Bob',studentid: []},
{id: 2, name : 'Sue',studentid: []},
{id: 3, name : 'Jean',studentid: []},
{id: 4, name : 'Jim',studentid: [
"500zz"
]},
{id: 5, name : 'Paul',studentid: [
"100zz",
"120zz",
"130zz"
]}
];
var students = [
{_id: "100zz", name : 'Betty'},
{_id: "120zz", name : 'Bob'},
{_id: "500zz", name : 'Billy'}
];
console.log(
teachers.filter(
(set => item => set.has(item.studentid))(new Set(students.map(item => item._id)))
)
)
I would like the result to include only the teachers Jim and Paul ( with all associated data )... not sure what I need to add or do? The array of studentid's is throwing me for a loop.
const teachers = [
{ id: 1, name: "Bob", studentid: [] },
{ id: 2, name: "Sue", studentid: [] },
{ id: 3, name: "Jean", studentid: [] },
{ id: 4, name: "Jim", studentid: ["500zz"] },
{ id: 5, name: "Paul", studentid: ["100zz", "120zz", "130zz"] }
];
const students = [
{ _id: "100zz", name: "Betty" },
{ _id: "120zz", name: "Bob" },
{ _id: "500zz", name: "Billy" }
];
// Filter teachers with students greater than 0.
const filtered = teachers.filter(x => x.studentid.length > 0);
// Map teachers with Students
const teachersWithStudents = filtered.map(x => {
const stu = students
.map(student => {
// Determine whether or not teacher 'studentid' contains student '_id'
const hasStudent = x.studentid.includes(student._id);
// Teacher has student
if (hasStudent) {
return {
id: student._id,
name: student.name
};
}
// Teacher does not have student
return false;
})
.filter(x => x); // filter objects that are not false
// Return teacher object with student (stu) objects
return {
...x,
studentid: stu
};
// Return those with matches only
}).filter(x => x.studentid.length > 0);
console.log(teachersWithStudents);

How to query a document with the highest value of a field

Let's say I have a collection of documents. To make this simpler, let's say all these documents have just 2 fields, name and id, like below.
I want to get the document with the greatest value of "id". Can I use the .find({}) with some parameters? If so, I can't figure out which parameter would find me the max value of a certain field.
[
{
name: "name1",
id: 1
}
{
name: "name2",
id: 2
}
{
name: "name1",
id: 3
}
{
name: "name1",
id: 0
}
]
let documents = [
{
name: "name1",
id: 1
},
{
name: "name2",
id: 2
},
{
name: "name1",
id: 3
},
{
name: "name1",
id: 0
}
];
let max = documents.sort( (a, b) => a.id > b.id ? -1 : 1)[0]
console.log( max );
How about
let maxIdDocument = documents.sort( (a, b) => a.id > b.id ? 1 : -1)[0]
First, sort in descending order, then get the first one:
const arr = [{
name: "name1",
id: 1
},
{
name: "name2",
id: 2
},
{
name: "name1",
id: 3
},
{
name: "name1",
id: 0
}
];
const [greatest] = arr.sort(({ id: a }, { id: b }) => b - a);
console.log(greatest);
You can sort that array and with the function pop get the object with the greatest id.
arr.slice() // This is to avoid a mutation on the original array.
let arr = [ { name: "name1", id: 1 }, { name: "name2", id: 2 }, { name: "name1", id: 3 } , { name: "name1", id: 0 } ],
greatest = arr.slice().sort(({id: a}, {id: b}) => a - b).pop();
console.log(greatest);
.as-console-wrapper { min-height: 100%; }

Categories