Replace or push to array in javascript - javascript

I have an array of orders and when i recieve a message from my websocket with a new placement order or a modified order i want to check against my orders array, if there is an exisitng order with the websocket message replace the object in the array with the websocket message, else push it to the array.
example:
const orderArr = [
{
id: 1,
item: 'apple',
price: 20
},
{
id: 2,
item: 'mango',
price: 10
},
{
id: 3,
item: 'cucumber',
price: 300
}
]
const webSocketOrder = {
id: 1,
item: 'apple',
price: 40
}
// what should happen to the order array
[
{
id: 1,
item: 'apple',
price: 40
},
{
id: 2,
item: 'mango',
price: 10
},
{
id: 3,
item: 'cucumber',
price: 300
}
]
but if the webSocketOrder is a new item with a new id it should be added as a new item in the orderArr
what i have done
const foundOrder = orderArr.find(
(x) => x.id === webSocketOrder.id
);
if (foundOrder) {
orderArr.map((ord) =>
ord.id === webSocketOrder.id
? webSocketOrder
: ord
);
} else {
orderArr.unshift(webSocketOrder);
}
this doesnt work for some reason, please can someone help?

You can use find()/findIndex() to loop over the array just once.
const index = orderArr.findIndex((obj) => obj.id === webSocketOrder.id);
if (index === -1) {
orderArr.push(webSocketOrder);
} else {
orderArr[index] = webSocketOrder;
}

Related

How to deep filter in array with objects in JS

I have an array and want to get just object { id: 4, name: 'name4' },
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
},
I try in this way.
const name = 'name4';
example.forEach((item) => item.items.find((i) => i.name === name));
But get undefined.
You can using flatMap() to do it
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
]
},
{
id: '3456',
desc: 'sample2',
items: [
{ id: 4, name: 'name4' },
{ id: 5, name: 'testItem5' }
]
}]
const name = 'name4';
let result = example.flatMap(e => e.items).filter(d => d.name == name)
console.log(result)
this way...?
const example =
[ { id : '1234'
, desc : 'sample1'
, items:
[ { id: 1, name: 'name1' }
, { id: 2, name: 'testItem2' }
] }
, { id : '3456'
, desc : 'sample2'
, items:
[ { id: 4, name: 'name4' }
, { id: 5, name: 'testItem5' }
] } ];
const rechName = (s,arr) =>
arr.find( x => // find the first parent object
x.items.some( y => // containing the search
y.name === s )
)?.items // if one
.find( z => z.name === s ); // find it in!
console.log( rechName('name4', example) ) // -> { id: 4, name: 'name4' }
console.log( rechName('abc', example) ) // -> undefined
forEach doesn't do what you think it does. From the docs:
The forEach() method executes a provided function once for each array element.
...
Return value
undefined.
So if you want to use forEach you need to save the value:
const example =
[ { id : '1234'
, desc : 'sample1'
, items:
[ { id: 1, name: 'name1' }
, { id: 2, name: 'testItem2' }
] }
, { id : '3456'
, desc : 'sample2'
, items:
[ { id: 4, name: 'name4' }
, { id: 5, name: 'testItem5' }
] } ]
const results = []; // Store matches here
const name = 'name4';
example.forEach((item) => {
const res = item.items.find((i) => i.name === name);
if (res !== undefined) {
results.push(res);
}
});
console.log(results);
IMHO I would suggest a more functional approach using flatMap and filter instead of forEach.
Lastly, note that in my above snippet, I'm storing the results in an array as it's not entirely clear to me that you won't have multiple matches per your example. But if you're sure that you will only ever have one result then a simple for loop works better, especially if you have a large array of items:
let result = null;
for (let i = 0; i < example.length; i++) {
const res = example[i].items.find((j) => j.name === name);
if (res !== undefined) {
result = res;
break; // No need to iterate further
}
}
console.log(result);
You could use a recursive search function. Here's a detailed example:
// Applies the function recursively from the top of the data tree ("depth-first")
const
data = getData(),
id = 4,
result = findById(data, id);
console.log(result ?? `No item with id ${id} found`);
// Defines the function
function findById(haystack, needleId){
let needle = null; // Defaults to null if no match at or below this level
// Iterates through all the items at this level
for(const item of haystack){
if(item.id == needleId){
// Qapla': Quits early, passes honorable item up to previous level
needle = item;
return needle;
}
else {
// Checks children, grandchildren, etc, before continuing iteration
const nextHaystack = item.items;
if(nextHaystack?.length){
needle = findById(nextHaystack, needleId); // Recursive call
}
}
// Done searching children, continues to next iteration at this level
}
// Done searching this level, returns result up to previous level
return needle;
}
// Gets the initial data
function getData(){
return [
{
id: '1234',
desc: 'sample1',
items: [ { id: 1, name: 'name1' }, { id: 2, name: 'testItem2' } ]
},
{
id: '3456',
desc: 'sample2',
items: [ { id: 4, name: 'name4' }, { id: 5, name: 'testItem5' } ]
}
];
}

How to splice multiple values from array of objects which matches given nested array

I am trying to remove the array of objects if the given array of objects matches with the index but it is only removing the last index value.
How we can remove multiple values?
let idArr = [[{ index: 2 }], [{ index: 3 }]];
let obj = [
{
id: 1,
name: 'abc',
},
{
id: 2,
name: 'abc',
},
{
id: 3,
name: 'abc',
},
{
id: 4,
name: 'abc',
},
];
let data = obj.filter((item, i) =>
idArr.reduce((val) => val.find(({ index }) => i === index))
);
//expected output
[
{
id: 1,
name: 'abc',
},
{
id: 2,
name: 'abc',
},
];
I think that following code achieves what you're expecting
let data = obj.filter((obj, idx) => !idArr.find(id => id[0].index === idx));

How to get the aggregation of an array in javascript

I am trying to aggregate my list of orders im getting in my database into an array of orders with different prices.
Example of array from my db:
[{
id: 1,
price: 10,
item: 'apple'
}, {
id: 2,
price: 10,
item: 'apple',
}, {
id: 3,
price: 20,
item: 'apple'
}]
i want to aggregate the orders based on the price ... if the price is the same make them into one array
what i want to return:
[{
price: 10,
item: 'apple',
quantity: 2
}, {
price: 20,
item: apple,
quantity: 1
}]
so as seen above if the price is the same aggregate them to one object and increase the quantity and return that to my users.
const data = [{
id: 1,
price: 10,
item: 'apple'
}, {
id: 2,
price: 10,
item: 'apple',
}, {
id: 3,
price: 20,
item: 'apple'
}];
let x = data.reduce((items, item) => {
let found = false;
delete(item.id)
items.forEach(el => {
if (el.price == item.price && el.item == item.item) {
found = true;
el.quantity++;
}
})
if (!found) {
item.quantity = 1;
items.push(item)
}
return items
}, [])
console.log(x)

Remove a specific object from an object array, filtering by a key and value pair

Is there any quick way to remove a specific object from an object array, filtering by a key and value pair, without specifying an index number?
For example, if there was an object array like so:
const arr = [
{ id: 1, name: 'apple' },
{ id: 2, name: 'banana' },
{ id: 3, name: 'cherry' },
...,
{ id: 30, name: 'grape' },
...,
{ id: 50, name: 'pineapple' }
]
How can you remove only the fruit which has the id: 30 without using its index number?
I have already figured out one way like the following code, but it looks like a roundabout way:
for ( let i = 0; i < arr.length; i++) {
if ( arr[i].id === 30 ) {
arr.splice(i, 1);
}
}
with es6 standard, you can use the filter method
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
const arr = [
{ id: 1, name: 'apple' },
{ id: 2, name: 'banana' },
{ id: 3, name: 'cherry' },
{ id: 30, name: 'grape' },
{ id: 50, name: 'pineapple' }
];
// !== for strict checking
console.log(arr.filter(e => e.id !== 30))

Creating a shopping list from an array of ingredients (formatted as objects)

var ingredients = [
{ name: 'potatoes', quantity: 4 },
{ name: 'butter', quantity: 1 },
{ name: 'milk', quantity: 1, description: '1 cup' },
{ name: 'potatoes', quantity: 3 },
{ name: 'oil', quantity: 1, description: '3 cups' } ];
const shoppingList = [];
for (let i = 0; i < ingredients.length; i ++) {
for (let j = 0; j < shoppingList.length; j ++){
let ingredient = ingredients[i];
let shoppingListItem = shoppingList[j];
if(ingredient === shoppingListItem){
break;
}else if (roughDraftItem.name === shoppingListItem.name){
shoppingListItem.quantity += roughDraftItem.quantity;
} else {shoppingList.push(roughDraftItem);
}
}
}
When I run this code the shoppingList array comes back empty. When I take out the second loop the code doesn't have a problem and I get what I need
shoppingListItem = { name: 'potatoes', quantity: 1}
It seems to be a problem of trying to compare the Ingredients array to the shoppingList array (after an object has been added).
Your shoppingList is empty so its length = 0. The second loop of the array doesn't run, since it's told to run 0 times.
You don't need the second loop to add an object to the shoppingList, so I would remove it.
As others have said, shoppingList starts with a length of 0, so the 2nd loop will never run. Also, if you're trying to sum the quantity of items with the same name, you could use reduce to simplify things:
const ingredients = [
{ name: 'potatoes', quantity: 4 },
{ name: 'butter', quantity: 1 },
{ name: 'milk', quantity: 1, description: '1 cup' },
{ name: 'potatoes', quantity: 3 },
{ name: 'oil', quantity: 1, description: '3 cups' } ];
const result = ingredients.reduce((acc, curr) => {
const exists = acc.find(item => item.name === curr.name);
if (exists) {
exists.quantity += curr.quantity;
return acc;
}
return [...acc, curr]
}, []);
console.log(result);
You can use Array.prototype.reduce and ES6 object destructuring assignment to make an aggregation of ingredients by their name, and Array.prototype.map to generate the desired output:
This solution is more declarative than nested for loops and can work with any amount of repetitive items:
var ingredients = [
{ name: 'potatoes', quantity: 4 },
{ name: 'butter', quantity: 1 },
{ name: 'milk', quantity: 1, description: '1 cup' },
{ name: 'potatoes', quantity: 3 },
{ name: 'oil', quantity: 1, description: '3 cups' }
];
// Aggregate `quantity` by `name`
var dataObj = ingredients.reduce((all, {name, quantity}) => {
all[name] = (all[name] || 0) + quantity;
return all;
}, {});
// Generate the result
var shoppingList = Object.keys(dataObj).map(ing => ({name: ing, quantity: dataObj[ing]}));
console.log(shoppingList);

Categories