I think I'm having trouble understanding the fundamentals of updating an array in Javascript. I have a cope snippet that is trying to do something to the effect of what I'll paste below.
I'll update the value of something in request.quantities, then the next reference to it takes the original value instead of the updated one. Can someone please explain to me where my disconnect is?
For example, the expected output for 'order' from this function should be:
[
{name: 'apple', batch: '12345', quantity: 5},
{name: 'orange', batch: '23456', quantity: 10},
{name: 'banana', batch: '34567', quantity: 3},
{name: 'banana', batch: '99999', quantity: 12},
]
But it winds up being:
[
{name: 'apple', batch: '12345', quantity: 5},
{name: 'orange', batch: '23456', quantity: 10},
{name: 'banana', batch: '34567', quantity: 3},
{name: 'banana', batch: '99999', quantity: 15},
]
let request = {
products:['apple', 'orange', 'banana'],
quantities:[5, 10, 15]
}
let stock = [
{name: 'apple', batch: '12345', quantity: 50},
{name: 'orange', batch: '23456', quantity: 1000},
{name: 'banana', batch: '34567', quantity: 3},
{name: 'banana', batch: '99999', quantity: 500},
]
let order = []
for (let i = 0; i < request.products.length; i++) {
for (let j = 0; j < stock.length; j++) {
if (request.products[i] == stock[j].name) {
if (stock[j].quantity - request.quantities[i] > 0) {
order.push({name: request.products[i], batch: stock[j].batch, quantity: request.quantities[i]})
stock[j].quantity = stock[j].quantity - request.quantities[i]
request.quantities[i] = 0
} else {
order.push({name: request.products[i], batch: stock[j].batch, quantity: stock[j].quantity})
stock[j].quantity = 0
request.quantities[i] = request.quantities[i] - stock[j].quantity
}
}
}
}
There's just a small logic error here. You need to set the request quanities in your else statement before you set the stock for that item quantity to 0.
const request = {
products: ['apple', 'orange', 'banana'],
quantities: [5, 10, 15],
};
const stock = [
{ name: 'apple', batch: '12345', quantity: 50 },
{ name: 'orange', batch: '23456', quantity: 1000 },
{ name: 'banana', batch: '34567', quantity: 3 },
{ name: 'banana', batch: '99999', quantity: 500 },
];
const order = [];
for (let i = 0; i < request.products.length; i++) {
for (let j = 0; j < stock.length; j++) {
if (request.products[i] == stock[j].name) {
if (stock[j].quantity - request.quantities[i] > 0) {
order.push({
name: request.products[i],
batch: stock[j].batch,
quantity: request.quantities[i],
});
stock[j].quantity = stock[j].quantity - request.quantities[i];
request.quantities[i] = 0;
} else {
order.push({
name: request.products[i],
batch: stock[j].batch,
quantity: stock[j].quantity,
});
/* Set request quantity first */
request.quantities[i] = request.quantities[i] - stock[j].quantity;
stock[j].quantity = 0;
}
}
}
}
console.log(order)
Related
I need to split data from BE and then sort by some prefix.
Example of array ->
let dataFromBE = [
{name: 'item one' , id: 1},
{name: 'item two' , id: 2},
{name: 'TEST:1' , id: 3},
{name: 'TEST:1' , id: 4},
{name: 'ASC item' , id: 5},
{name: 'some item' , id: 6},
{name: 'ASC item' , id: 6},
];
What I need ? To sort items with prefix 'TEST:' in first ( top ) array and sort other items alphabetically.
This is my way but maybe is not enough good
const itemsWithPrefix = tags?.filter(
(item) => item.name && item.name.toUpperCase().startsWith('TEST:')
);
const otherItems = tags?.filter(
(item) => item.name && !item.name.toUpperCase().startsWith('TEST:')
);
let mergedArr: any[] = [];
if (itemsWithPrefix && otherItems) {
mergedArr = [...itemsWithPrefix, ...otherItems?.sort((a, b) => (a.name > b.name ? 1 : -1))];
}
Is there a possibility for this to be done without creating two separate sequences, but only iteration through one? Thank you. And any other attempt to be more readable than mine is totally fine.
Use sort() with a custom sort function that gives priority to "TEST"
let dataFromBE = [
{name: 'item one' , id: 1},
{name: 'item two' , id: 2},
{name: 'TEST:1' , id: 3},
{name: 'TEST:1' , id: 4},
{name: 'ASC item' , id: 5},
{name: 'some item' , id: 6},
{name: 'ASC item' , id: 6},
];
dataFromBE.sort((a,b) => {
const aIsTEST = a.name.toUpperCase().startsWith('TEST:');
const bIsTEST = b.name.toUpperCase().startsWith('TEST:');
if (aIsTEST && !bIsTEST) return -1;
if (!aIsTEST && bIsTEST) return 1;
return a.name.localeCompare(b.name);
});
console.log(dataFromBE);
you can use includes() method instead of comparison inorder to avoid exact matching
let dataFromBE = [
{name: 'item one' , id: 1},
{name: 'TEST: ' , id: 2},
{name: 'TEST:1' , id: 3},
{name: 'TEST:2' , id: 4},
{name: 'ASC item' , id: 5},
{name: 'some item' , id: 6},
{name: 'ASC item' , id: 6},
];
dataFromBE.sort((a,b) => {
if (a.name.includes("TEST:") && !(b.name.includes("TEST:"))) return -1;
if (!(a.name.includes("TEST:")) && b.name.includes("TEST:")) return 1;
return a.name.localeCompare(b.name);
});
console.log(dataFromBE)
try using sort
let dataFromBE = [
{name: 'item one' , id: 1},
{name: 'item two' , id: 2},
{name: 'TEST:1' , id: 3},
{name: 'TEST:1' , id: 4},
{name: 'ASC item' , id: 5},
{name: 'some item' , id: 6},
{name: 'ASC item' , id: 6},
];
dataFromBE.sort((a, b) => {
const nameA = a.name.toUpperCase();
const nameB = b.name.toUpperCase();
if (nameA.startsWith("TEST") && !nameB.startsWith("TEST")) return -1;
if (!nameA.startsWith("TEST") && nameB.startsWith("TEST")) return 1;
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
});
console.log(dataFromBE)
Hi i'm trying to organize this data, i can arrange this product list by index of userSettings.categories array, i need also to sort the products by id like the sortedProducts property, this is what i've been trying for now, thanks in advance community.
let products = [
{id: 1, name: 'Brasilian', category: 'cofee'},
{id: 2, name: 'Colombian', category: 'cofee'},
{id: 3, name: 'Apple', category: 'fruit'},
{id: 4, name: 'Strawberry', category: 'fruit'},
{id: 5, name: 'Banana', category: 'fruit'},
{id: 6, name: 'Pepper', category: 'spices'},
{id: 7, name: 'Salt', category: 'spices'}
]
let userSettings = {
categories: [
{name: 'fruit', sortedProducts: [4, 3, 5]},
{name: 'spices', sortedProducts: [6, 7]},
{name: 'cofee', sortedProducts: [2, 1]},
]
}
let arrangedProducts = userSettings.categories.map(c => products.filter(o => o.category == c.name));
console.log(arrangedProducts);
expectedOutput = [
[
{id: 4, name: 'Strawberry', category: 'fruit'},
{id: 3, name: 'Apple', category: 'fruit'},
{id: 5, name: 'Banana', category: 'fruit'}
],
[
{id: 6, name: 'Pepper', category: 'spices'},
{id: 7, name: 'Salt', category: 'spices'}
],
[
{id: 2, name: 'Colombian', category: 'cofee'},
{id: 1, name: 'Brasilian', category: 'cofee'}
]
];
console.log(expectedOutput);
You can try
let arrangedProducts = userSettings.categories.map(
c => c.sortedProducts.map(
id => products.find(product => product.id === id)
)
);
Or if you have a lot of items in the future and want it to run faster, you can use hash table
const hashProduct = products.reduce((a, b) => ({...a, [b.id]: b}), {});
console.log(
userSettings.categories.map(
c => c.sortedProducts.map(id => hashProduct[id])
)
);
Try:
let products=[{id:1,name:"Brasilian",category:"cofee"},{id:2,name:"Colombian",category:"cofee"},{id:3,name:"Apple",category:"fruit"},{id:4,name:"Strawberry",category:"fruit"},{id:5,name:"Banana",category:"fruit"},{id:6,name:"Pepper",category:"spices"},{id:7,name:"Salt",category:"spices"}]
let userSettings={categories:[{name:"fruit",sortedProducts:[4,3,5]},{name:"spices",sortedProducts:[6,7]},{name:"cofee",sortedProducts:[2,1]}]};
let result = []
userSettings.categories.forEach((e) => { let arr = []; e.sortedProducts.forEach(f => arr.push(products.filter(g => g.id == f))); result.push(arr) })
console.log(result);
You can sort by the indexOf in the sortedProducts array
userSettings.categories
.map(c => products
.filter(o => o.category == c.name)
.sort((a, b) =>
c.sortedProducts.indexOf(a.id) - c.sortedProducts.indexOf(b.id)))
let products = [{
id: 1,
name: 'Brasilian',
category: 'cofee'
},
{
id: 2,
name: 'Colombian',
category: 'cofee'
},
{
id: 3,
name: 'Apple',
category: 'fruit'
},
{
id: 4,
name: 'Strawberry',
category: 'fruit'
},
{
id: 5,
name: 'Banana',
category: 'fruit'
},
{
id: 6,
name: 'Pepper',
category: 'spices'
},
{
id: 7,
name: 'Salt',
category: 'spices'
}
]
let userSettings = {
categories: [{
name: 'fruit',
sortedProducts: [4, 3, 5]
},
{
name: 'spices',
sortedProducts: [6, 7]
},
{
name: 'cofee',
sortedProducts: [2, 1]
},
]
}
let expectedOutput = userSettings.categories.map(c => products.filter(o => o.category == c.name).sort((a, b) => c.sortedProducts.indexOf(a.id) - c.sortedProducts.indexOf(b.id)));
console.log(expectedOutput);
Suppose I have:
const fixed = {pear: 100, apple: 4}
const arr = [
{name: 'P1', pear: 150, apple: 2},
{name: 'P2', pear: 50, apple: 5},
{name: 'P3', pear: 450, apple: 1},
{name: 'P4', pear: 100, apple: 3},
]
and I want to have:
const result = [
{name: 'P1', pear: -50, apple: 2},
{name: 'P2', pear: 50, apple: -1},
{name: 'P3', pear: -350, apple: 3},
{name: 'P4', pear: 0, apple: 1},
]
So result has the same items of arr but with edited apple and pear values based on fixed object values.
The new pear (and apple) value should be fixed.pear - oldPearValue, so for example, for arr[0]:
fixed.pear - arr[0].pear = 100 - 150 = -50 --> result[0].pear = -50
Here is what I tried:
function difference(fixed, value) {
return value - fixed
}
const fixed = {pear: 100, apple: 4}
const arr = [
{name: 'P1', pear: 150, apple: 2},
{name: 'P2', pear: 50, apple: 5},
{name: 'P3', pear: 450, apple: 1},
{name: 'P4', pear: 100, apple: 3},
]
const dataset = arr.flatMap((d) => {
Object.entries(fixed).forEach(([key, value]) => {
return { ...d, [key]: difference(value, d[key]) }
})
})
console.log(dataset)
as you can see, the result is [ undefined, undefined, undefined, undefined ]..
You could get the entries and map new properties.
const
fixed = { pear: 100, apple: 4 },
arr = [{ name: 'P1', pear: 150, apple: 2 }, { name: 'P2', pear: 50, apple: 5 }, { name: 'P3', pear: 450, apple: 1 }, { name: 'P4', pear: 100, apple: 3 }],
dataset = arr.map(d => ({ ...d, ...Object.fromEntries(Object
.entries(fixed)
.map(([k, v]) => [k, v - d[k]])
) }));
console.log(dataset);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If the fixed object has to be a fixed object with same fields, then you can try this
const fixed = { pear: 100, apple: 4 };
const arr = [
{ name: 'P1', pear: 150, apple: 2 },
{ name: 'P2', pear: 50, apple: 5 },
{ name: 'P3', pear: 450, apple: 1 },
{ name: 'P4', pear: 100, apple: 3 }
];
let data = arr.map((item) => {
return { ...item, pear: fixed.pear - item.pear, apple: fixed.apple - item.apple };
});
console.log('checkk', data);
I'm trying to transform some data by using Lodash groupBy and map. Here is sample data:
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
I need that data in the format:
var data = [
{name: 'x', pricing: [{qty: 0, rate: 10}, {qty: 10, rate: 2}]},
{name: 'y', pricing: [{qty: 5, rate: 20}, {qty: 55, rate: 11}]}]
The following is my attempt:
var m = _.chain(data)
.groupBy(data, 'name')
.map( function(i) {
return {
name: _.first(i).name,
pricing: _.map(i, function(r) {
return _.pick(r, ['qty', 'rate'])
})
}
})
This produces
[{
"name": "x",
"pricing": [
{"qty": 0, "rate": 10},
{"qty": 10, "rate": 2},
{"qty": 5,"rate": 20},
{"qty": 55,"rate": 11}]
}]
I've been unable to figure out what I'm doing wrong. Maybe this isn't even valid and there is a better way?
You need to map new object and get the picked values.
var data = [{ name: 'x', qty: 0, rate: 10 }, { name: 'x', qty: 10, rate: 2 }, { name: 'y', qty: 5, rate: 20 }, { name: 'y', qty: 55, rate: 11 }],
result = _(data)
.groupBy('name')
.map((pricing, name) => ({
name,
pricing: _.map(pricing, _.partialRight(_.pick, ['qty', 'rate']))
}))
.value();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You don't need to use lodash for this - standard Javascript array methods work just fine. Reduce into an object indexed by name, then get that object's values:
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
const obj = data.reduce((a, { name, ...rest }) => {
if (!a[name]) a[name] = { name, pricing: [] };
a[name].pricing.push(rest);
return a;
}, {});
const output = Object.values(obj);
console.log(output);
You can do that using reduce()
var data = [
{name: 'x', qty: 0, rate: 10},
{name: 'x', qty: 10, rate: 2},
{name: 'y', qty: 5, rate: 20},
{name: 'y', qty: 55, rate: 11}]
let res = data.reduce((ac,a) => {
let i = ac.findIndex(x => x.name === a.name);
if(i === -1) i = ac.push({name:a.name,pricing:[]}) - 1
ac[i].pricing.push({qty:a.qty,rate:a.rate});
return ac;
},[])
console.log(res);
Your code is actually fine, except for a small mistake. You start a chain with data, and then you try to groupBy the data. Since non of the items return true for this predicate, all are bundled under a single group, and this is the reason for your single object.
You need to change .groupBy(data, 'name') to .groupBy('name').
Example:
var data = [{ name: 'x', qty: 0, rate: 10 }, { name: 'x', qty: 10, rate: 2 }, { name: 'y', qty: 5, rate: 20 }, { name: 'y', qty: 55, rate: 11 }];
var m = _.chain(data)
.groupBy('name') // group by name, and not by data, 'name'
.map(function(i) {
return {
name: _.first(i).name,
pricing: _.map(i, function(r) {
return _.pick(r, ['qty', 'rate'])
})
}
})
console.log(m);
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
I have an array of objects:
var obj = [
{name: 'a1', type: 't1', price: 10},
{name: 'a1', type: 't1', price: 10},
{name: 'a2', type: 't2', price: 10},
{name: 'a1', type: 't2', price: 10},
];
I need to get this result:
[
{name: 'a1', type: 't1', price: 20},
{name: 'a1', type: 't2', price: 10},
{name: 'a2', type: 't2', price: 10}
]
I want to sum the item if, and only if, the properties name and type match. Any idea?
You can use reduce to group it into an object. Use Object.values to convert the object into array.
var obj = [
{name: 'a1', type: 't1', price: 10},
{name: 'a1', type: 't1', price: 10},
{name: 'a2', type: 't2', price: 10},
{name: 'a1', type: 't2', price: 10},
];
var result = Object.values(obj.reduce((c, v) => {
let k = v.name + '-' + v.type;
c[k] = c[k] || {...v, price: 0};
c[k].price += v.price;
return c;
}, {}));
console.log(result);
You could reduce into a Map and turn it back into an array:
var obj = [
{name: 'a1', type: 't1', price: 10},
{name: 'a1', type: 't1', price: 10},
{name: 'a2', type: 't2', price: 10},
{name: 'a1', type: 't2', price: 10},
];
const map = obj.reduce((map, { name, type, price }) => {
console.log('iter');
const key = name + '_' + type;
return map.set(key, (map.get(key) || 0) + price);
}, new Map());
const output = [...map.entries()].map(([key, val]) => {
const [name, type] = key.split('_');
return { name, type, price: val };
});
console.log(output);
You can try following (sum and sort by name and type)
var obj = [
{name: 'a1', type: 't1', price: 10},
{name: 'a1', type: 't1', price: 10},
{name: 'a2', type: 't2', price: 10},
{name: 'a1', type: 't2', price: 10},
];
// First create the result object where sum of price is done
var result = obj.reduce((a,c) => {
if(a[c.name + "_" + c.type]) {
a[c.name + "_" + c.type].price += c.price;
} else {
a[c.name + "_" + c.type] = c;
}
return a;
}, {});
// Get the values in an array
result = Object.values(result);
// Sort the array by name and then type
result.sort((a,b) => {
if(a.name === b.name) return a.type.localeCompare(b.type);
return a.name.localeCompare(b.name);
});
console.log(result);
You can use of Array.reduce to build up a new array considering your requirements.
const obj = [{
name: 'a1',
type: 't1',
price: 10,
},
{
name: 'a1',
type: 't1',
price: 10,
},
{
name: 'a2',
type: 't2',
price: 10,
},
{
name: 'a1',
type: 't2',
price: 10,
},
].reduce((tmp, x) => {
// Look if there is already a matching item in tmp
const findItem = tmp.find(y => y.name === x.name && y.type === x.type);
// It's not inside
if (!findItem) {
tmp.push(x);
return tmp;
}
// it is inside
findItem.price += x.price;
return tmp;
}, []);
console.log(obj);