Add together an array of objects - javascript

I am trying to add together an array of objects, using reduce however i can't get it work.
const testArray = [
{
"T1": 1
},
{
"T2": 12
},
{
"T3": 20
}
]
reduce function
const q = testArray.reduce((count, x) => count + x.P1Count);
outcome = 33

You could get the values and reduce the values as well.
const
add = (a, b) => a + b,
array = [{ "T1": 1 }, { "T2": 12 }, { "T3": 20 }],
total = array.reduce(
(s, o) => Object.values(o).reduce(add, s),
0
);
console.log(total);

The 2nd argument of the reduce() function will be the member of the array the reduce is being called on. In your case, which will be { T[i]: ... } where i = 1, 2, 3.
You can try this:
const testArray = [
{
"T1": 1
},
{
"T2": 12
},
{
"T3": 20
}
]
const x = testArray.reduce((count, x, index) => {
const key = `T${index+1}`; // prepare the dynamic key T1, T2,...
return count + x[key];
}, 0); // <-- 0 is the initial value of sum
console.log(x)

Related

Accessing the body of the response object

I am having what I think is a pretty trivial problem but somehow I can't find a solution to. I have a response body that looks like this:
{
"sizes": [
{
"43": 35
},
{
"42": 20
},
{
"38": 10
}
]
}
where the keys are shoe sizes and the value is quantity of each size. How do I access the sizes? What I currently have is this:
const sizesArray = response.data.sizes
const arr = Object.values(msizes);
console.log('arr', arr);
arr.map((i,a) => {
console.log('i',i);
console.log('a',a);
})
but i is then again a object {43: 35}
and a is just the index. I want somehow to assign the key to parameter called 'sizes' and the key to a parameter called quantity.
You can use Object.keys, a bit simpler than Object.entries
Example:
const data = { sizes: [{ "43": 35 }, { "42": 20 }, { "38": 10 }] };
const result = data.sizes.map((element, index) => {
let obj = Object.keys(element); // returns an array of keys
let key = obj[0]; // first element is the only key
let quantity = element[key]; // bracket notation, key is an string, not number
console.log("size", key);
console.log("quantity", quantity);
});
You can just iterate the sizes array, using reduce to append the keys of each object to an output array of sizes:
const data = { sizes: [{ "43": 35 }, { "42": 20 }, { "38": 10 }] }
const sizes = data.sizes.reduce((acc, s) => acc.concat(Object.keys(s)), [])
console.log(sizes)
If you want sizes and quantities, you can take a similar approach, just generate an object which accumulates both sets of values:
const data = { sizes: [{ "43": 35 }, { "42": 20 }, { "38": 10 }] }
const { sizes, quantities } = data.sizes
.reduce((acc, s) => {
acc.sizes = acc.sizes.concat(Object.keys(s))
acc.quantities = acc.quantities.concat(Object.values(s))
return acc
},
{ sizes : [], quantities : [] })
console.log(sizes)
console.log(quantities)
You were on the right track :)
Use Object.keys() to get an array of your keys (shoe-sizes). Then use the map()-function to create a new array. Use the index of map() to access the quantity in your response.
const sizesArray = response.data.sizes
const sizes = Object.keys(sizesArray);
const result = sizes.map((element, index) => ({
size: element,
quantity: sizesArray[index]
}));
console.log(result);

How to merge a nested array of objects in javascript with a specific shape

I am trying to merge an array of objects by summing up the totals of each key-value pair under the totals object. For example, the below array would yield one object with a totals object of 3 apples and 5 oranges. This should be dynamic. If pears were to be a key in another object, the resulting object would include three keys under the totals object: apples, oranges, and pears.
Sample Input:
[
{
summary: {
totals: {
apples: 2,
oranges: 3
}
}
},
{
summary: {
totals: {
apples: 1,
oranges: 2
}
}
}
]
Expected Output:
{
summary:{
totals:{
apples:3,
oranges:5
}
}
}
What I've tried:
function mergeObjects(arr) {
let shape = {
summary:{
totals:{}
}
}
return arr.reduce((prev, cur) => {
if(cur.summary.totals.apples){
shape.summary.totals.apples.push(cur.summary.totals.apples)
}
}, shape);
}
Using Array#reduce, iterate over the array while updating an object
In every iteration, using Object#entries and
, iterate over the current totals pairs and update the accumulator.
const arr = [
{ summary: { totals: { apples: 2, oranges: 3 } } },
{ summary: { totals: { apples: 1, oranges: 2 } } },
];
const res = arr.reduce((map, current) => {
const { totals: currentTotals = {} } = current.summary ?? {};
const { totals } = map.summary;
Object.entries(currentTotals).forEach(([ key, value ]) => {
totals[key] = (totals[key] ?? 0) + value;
});
return map;
}, { summary: { totals: {} } });
console.log(res);
You can try something like. Just loop through the array and sum up apples and oranges.
const arr = [
{
summary: {
totals: {
apples: 2,
oranges: 3,
},
},
},
{
summary: {
totals: {
apples: 1,
oranges: 2,
},
},
},
];
function mergeObjects(arr) {
let shape = {
summary:{
totals:{
apples:0,
oranges:0
}
}
}
arr.forEach(x => {
if(x.summary.totals.apples){
shape.summary.totals.apples += x.summary.totals.apples;
shape.summary.totals.oranges += x.summary.totals.oranges;
}
});
return shape;
}
let result = mergeObjects(arr);
console.log(result);
The second option of the reduce function initializes the value.
And the initialized value can be used in prev!
[1] store the value in prev.
[2] prev can accumulate values. You have to return to use the accumulated value. If not returned, the value will be undefined.
[3] apples is not an array type, so you cannot use the push method. it is a number type, you must use a numeric operator.
function mergeObjects(arr) {
const shape = {
summary: {
totals: {},
},
};
return arr.reduce((prev, cur) => {
const { apples, oranges } = cur.summary.totals;
// [1]
prev.summary.totals.apples
// [3]
? (prev.summary.totals.apples += apples)
: (prev.summary.totals.apples = apples);
prev.summary.totals.oranges
? (prev.summary.totals.oranges += oranges)
: (prev.summary.totals.oranges = oranges);
// [2]
return prev;
}, shape);
}
tips!
Use Destructuring Assignment
const { apples, oranges } = cur.summary.totals;
Use Ternary Operator
prev.summary.totals.apples
? (prev.summary.totals.apples += apples)
: (prev.summary.totals.apples = apples);
Make code look nice!
You can combine Object.entries() with Array#reduce() and Array.forEach()
Code:
const data = [{summary: {totals: {apples: 2,oranges: 3}}},{summary: {totals: {apples: 1,oranges: 2}}}]
const result = data.reduce((a, c) => {
Object
.entries(c.summary.totals)
.forEach(([k, v]) => a.summary.totals[k] += v)
return a
},
{ summary: { totals: { apples: 0, oranges: 0 } } })
console.log(result)

Divide object array elements into groups of n each javascript

I have an Object as below:
const boxOfFruits = {
apples: [
{
name: "Kashmiri",
},
{
name: "Washington",
},
{
name: "Himalayan",
},
{
name: "Fuji",
}
],
oranges: [
{
name: "Nagpur",
},
{
name: "Clementine",
},
],
mangoes: [
{
name: "Totapuri",
},
{
name: "Alphonso",
},
{
name: "Langda",
},
],
}
I want to divide these fruits into boxes; maximum of n each, let's say where n is 3 and apples, oranges and mangoes are equally distributed.
So the output in this case would be:
box_1 = [{name: "Kashmiri"}, {name: "Nagpur"},{name: "Totapuri"}];
box_2 = [{name: "Washington"}, {name: "Clementine"},{name: "Alphonso"}];
box_3 = [{name: "Himalayan"},{name: "Langda"}, {name: "Fuji"}];
The type of fruits(apple,oranges,etc)/keys in object can increase/decrease and n is also variable. In case total fruits are less than n, then it would be just 1 box of fruits.
What I have tried so far:
Using Lodash, I am calculating the minimum and the maximum fruits in a single type:
const minFruitType = _.min(Object.values(basket).map((eachBasket: any) => eachBasket.length));
Total teams will the sum of the fruits / n
Will distribute the minimum fruits (l) in the first l boxes and fill the rest with the remaining fruits at every iteration while at the start of every iteration will calculate the minimum type of fruits again.
You can use Object.values(), array#reduce and array#forEach to transform your object.
const boxOfFruits = { apples: [ { name: "Kashmiri", }, { name: "Washington", }, { name: "Himalayan", }, ], oranges: [ { name: "Nagpur", }, { name: "Clementine", }, ], mangoes: [ { name: "Totapuri", }, { name: "Alphonso", }, { name: "Langda", }, ], },
result = Object.values(boxOfFruits).reduce((r, arr) => {
arr.forEach((o,i) => {
const key = `box_${i+1}`;
r[key] ??= r[key] || [];
r[key].push(o)
});
return r;
},{});
console.log(result);
The easiest way would be to use lodash.js's zip() function:
const boxes = _.zip( Object.values(boxOfFruits) );
Note that _.zip() will give you undefined values when the source arrays are different lengths, so you'll need/want to filter those out:
const boxes == _.zip( Object.values(boxOfFruits) )
.map(
box => box.filter(
x => x !== undefined
)
);
But that will not distribute the fruits evenly. For that, it shouldn't get much for difficult than this:
function distribute(boxOfFruits, n) {
const boxes = [];
const fruits = Object.keys(boxOfFruits);
for ( const fruit of fruits ) {
let i = 0;
const items = boxOfFruits[fruit];
for (const item of items) {
boxes[i] = !boxes[i] ?? [];
boxes[i] = boxes[i].push(item);
++i;
i = i < n ? i : 0 ;
}
}
return boxes;
}
A modified version of #Nicholas Carey's answer worked for me:
function distribute(boxOfFruits, n) {
let boxes = [];
let totalFruits = Object.values(boxOfFruits)
.reduce((content, current) => content + current.length, 0);
let maxBoxes = Math.ceil(totalFruits / 4);
Object.values(boxOfFruits).forEach((fruits) => {
let i = 0;
fruits.forEach((fruit) => {
boxes[i] ??= boxes[i] || [];
boxes[i].push(fruit);
++i;
i = i < (n+1) ? i : 0;
});
});
// Extra boxes created, redistribute them to
// starting boxes
let newBoxes = teams.slice(0, maxBoxes);
let pendingBoxes = teams.slice(maxBoxes);
let pendingFruits = pendingBoxes.flat();
let distributedBoxes = newBoxes.map((eachBox) => {
let required = n - eachBox.length;
if (required > 0) {
eachBox.push(...pendingFruits.splice(0, required));
}
return eachBox;
});
return distributedBoxes;
}
Code is pretty much the same as Nicholas's accept the below changes:
Directly fetched the values and iterated over those
empty array creation was failing, this way works
and checking on the max box size with n+1 instead of n

How can I sort this array in Discord.js?

I have an array, that looks like this(size changes):
[
{ '385090261019131915': 34 },
{ '746430449240375297': 2 },
{ '810189312175374408': 1 },
{ '830832432680009789': 8 },
{ '850073735272988692': 1 }
]
The first value is the member id, the second how many messages the user has.
How can I sort the array, to get the first 10 members, sorted by their messages send?
The code:
if(command === 'leaderboard'){
const list = []
fs.readdirSync('./db/user/messages').forEach(file => {
const user = JSON.parse(fs.readFileSync(`./db/user/messages/${file}` , 'utf-8'))
userid = file.replace('.json','');
const entry = {[userid] : user.userall}
list.push(entry)
})
}
To sort an array by numbers, you can use the .sort() method with a compare function that subtracts the second value from the first one:
const arr = [34, 2, 1, 8, 1]
const sorted = arr.sort((a, b) => b - a)
console.log({ sorted })
As you're using objects, you should sort by an object key, but you're using the user ID as the key, so you don't know them. You can, however, get the value using the [Object.values()][2] method to get the value(s) and sort by them:
const arr = [
{ '385090261019131915': 34 },
{ '746430449240375297': 2 },
{ '810189312175374408': 1 },
{ '830832432680009789': 8 },
{ '850073735272988692': 1 }
]
const sorted = arr.sort((a, b) => Object.values(b)[0] - Object.values(a)[0])
console.log({ sorted })
Don't forget that Object.values() returns an array so you'll need to compare the first element.
However, instead of using the user ID as the key and the points as the value, I'd use two different keys in the object, one for the ID and one for the score:
const list = [
{ id: '385090261019131915', score: 34 },
{ id: '746430449240375297', score: 2 },
{ id: '810189312175374408', score: 1 },
{ id: '830832432680009789', score: 8 },
{ id: '850073735272988692', score: 1 }
]
const sortedList = list.sort((a, b) => b.score - a.score)
console.log({ sortedList })
And the final code:
if (command === 'leaderboard') {
const list = []
fs.readdirSync('./db/user/messages').forEach((file) => {
const user = JSON.parse(
fs.readFileSync(`./db/user/messages/${file}`, 'utf-8'),
)
const userId = file.replace('.json', '')
list.push({ id: userId, score: user.userall })
});
// sort by score
const sortedList = list.sort((a, b) => b.score - a.score)
}

How to group by and get the element having max value - javascript/node.js

I have the following array. I am trying to get the element having maximum id by grouping by the entryId in node.js.
[
{
"entryId": "7wpNAXhYI",
"id": 5
},
{
"entryId": "7wpNAXhYI",
"id": 6
},
{
"entryId": "5PGB23RI",
"id": 7
},
{
"entryId": "5PGB23RI",
"id": 8
}
]
The typical sql syntax would like as follows:
select entryId, max(id) from table group by entryId
I have written the following code which would get just the max without grouping by. Any help how to modify the following code or any simple approach available.
function getMax(array) {
var max = {};
for (var i = 0; i < array.length; i++) {
if (parseInt(array[i].id) > (parseInt(max.id) || 0))
max = array[i];
}
return max;
}
You can use sort in descending order and return the first element
var a = [{
"entryId": "7wpNAXhYI",
"id": 5
},
{
"entryId": "7wpNAXhYI",
"id": 6
},
{
"entryId": "5PGB23RI",
"id": 7
},
{
"entryId": "5PGB23RI",
"id": 8
}
]
function getMax(array) {
return array.sort((a, b) => b.id - a.id)[0]
}
console.log(getMax(a));
You can use 2 reduce the first one is to group the array. The second one is to get the max using Math.max()
var arr = [{"entryId":"7wpNAXhYI","id":5},{"entryId":"7wpNAXhYI","id":6},{"entryId":"5PGB23RI","id":7},{"entryId":"5PGB23RI","id":8}]
var result = Object.entries(arr.reduce((c, {entryId,id}) => {
(c[entryId] = c[entryId] || []).push(id);
return c;
}, {})).reduce((c, [k, v]) => Object.assign(c, {[k]: Math.max(...v)}), {});
console.log(result);
You can use map if you prefer an array:
var arr = [{"entryId":"7wpNAXhYI","id":5},{"entryId":"7wpNAXhYI","id":6},{"entryId":"5PGB23RI","id":7},{"entryId":"5PGB23RI","id":8}]
var result = Object.entries(arr.reduce((c, {entryId,id}) => {
(c[entryId] = c[entryId] || []).push(id);
return c;
}, {})).map(([entryId, id]) => ({entryId,id: Math.max(...id)}))
console.log(result);
You can use reduce to get the maximum.
function getMax(arr) {
max = arr.reduce((M, o) => M > o.id ? M : o, {id:-Infinity});
}

Categories

Resources