Having an array like this:
const data = [
{
"name": "Dave",
"coins": 14,
"weapons": 2,
"otherItems": 3,
"color": "red"
},
{
"name": "Vanessa",
"coins": 18,
"weapons": 1,
"otherItems": 5,
"color": "blue"
},
{
"name": "Sharon",
"coins": 9,
"weapons": 5,
"otherItems": 1,
"color": "pink"
},
{
"name": "Walter",
"coins": 9,
"weapons": 2,
"otherItems": 4,
"color": "white"
}
]
How to count sum of coins, weapons and otherItems using ES6 features? (I'm not attached to this: any simple method would be good.)
data.reduce((first, last) => first + last) generates a chain of [object Object][object Object]s...
You have to process every field separately (note that when you don't specify second parameter for reduce it will take first array object as seed and start processing from the second one):
const data = [
{
"name": "Dave",
"coins": 14,
"weapons": 2,
"otherItems": 3,
"color": "red"
},
{
"name": "Vanessa",
"coins": 18,
"weapons": 1,
"otherItems": 5,
"color": "blue"
},
{
"name": "Sharon",
"coins": 9,
"weapons": 5,
"otherItems": 1,
"color": "pink"
},
{
"name": "Walter",
"coins": 9,
"weapons": 2,
"otherItems": 4,
"color": "white"
}
]
let result = data.reduce((a,c)=> ({
coins: a.coins + c.coins,
weapons: a.weapons + c.weapons,
otherItems: a.otherItems + c.otherItems })
)
console.log(result);
You could take an array of wanted keys for the sums and create an object for the sums and add the wanted values.
const
data = [{ name: "Dave", coins: 14, weapons: 2, otherItems: 3, color: "red" }, { name: "Vanessa", coins: 18, weapons: 1, otherItems: 5, color: "blue" }, { name: "Sharon", coins: 9, weapons: 5, otherItems: 1, color: "pink" }, { name: "Walter", coins: 9, weapons: 2, otherItems: 4, color: "white" }],
keys = ['coins', 'weapons', 'otherItems'],
sums = data.reduce(
(r, o) => (keys.forEach(k => r[k] += o[k]), r),
Object.fromEntries(keys.map(k => [k, 0]))
);
console.log(sums);
You can use Array.prototype.reduce for this.
To make it a little bit more flexible and dynamic, make a Set of keys you want to get a count of.
Then go through each key in the Set and if that key is in the obj, sum it up in an accumulator object in the reduce callback:
const data = [{"name":"Dave","coins":14,"weapons":2,"otherItems":3,"color":"red"},{"name":"Vanessa","coins":18,"weapons":1,"otherItems":5,"color":"blue"},{"name":"Sharon","coins":9,"weapons":5,"otherItems":1,"color":"pink"},{"name":"Walter","coins":9,"weapons":2,"otherItems":4,"color":"white"}]
//Keys to count
const keys = new Set(["coins", "weapons", "otherItems"]);
const count = data.reduce((acc, obj) => {
const objKeys = keys.forEach(key => {
if (obj.hasOwnProperty(key)) {
acc[key] = (acc[key] || 0) + obj[key];
}
});
return acc;
}, {});
console.log(count);
Your idea is right, you need to use reduce method. The problem is that you're summing two objects, not their properties. All you need to do is change the code to the following (to sum the coins):
data.reduce((first, last) => first.coins + last.coins, 0)
And following for weapons:
data.reduce((first, last) => first.weapons + last.weapons, 0)
Related
I have one array of object which looks something like this:-
const myObjArr = [
{
"channelName": "AFM",
"21-Apr-2022": 2,
"22-Apr-2022": 2,
"27-Apr-2022": 1,
"29-Apr-2022": 3,
"19-Apr-2022": 1
},
{
"channelName": "Organic Others",
"6-Apr-2022": 6,
"27-Apr-2022": 4,
"7-Apr-2022": 3,
"21-Apr-2022": 1,
"8-Apr-2022": 1
},
{
"channelName": "website",
"27-Apr-2022": 1
}
]
now I want to add one more key, which is named as total in each object of this array which hold sum of all date keys to clarify I am providing the required output in the reqArray variable below
reqArray = [
{
"channelName": "AFM",
"21-Apr-2022": 2,
"22-Apr-2022": 2,
"27-Apr-2022": 1,
"29-Apr-2022": 3,
"19-Apr-2022": 1,
"total":9
},
{
"channelName": "Organic Others",
"6-Apr-2022": 6,
"27-Apr-2022": 4,
"7-Apr-2022": 3,
"21-Apr-2022": 1,
"8-Apr-2022": 1
"total": 15
},
{
"channelName": "website",
"27-Apr-2022": 1,
"total" : 1
}
]
function addFieldsForItem (arr = []) {
arr.forEach(function(item) {
let total = 0;
Object.keys(item).forEach(function(key) {
if (typeof item[key] === 'number') {
total = total + item[key]
}
})
item.total = total
})
return arr;
}
Let's say I have an array of objects:
Objects = [
{ "id": 1, "name": Joseph, function: "preacher"},
{ "id": 2, "name": Ann, function: "singer"},
{ "id": 3, "name": Miles, function: "preacher"},
{ "id": 4, "name": Jack, function: "singer"},
{ "id": 5, "name": Igor, function: "secretary"}
];
And also an array of properties:
sort = ['function', 'name'];
I have to sort the Objects array, using a combination of properties(sort array).
So I did it like this:
const intlCollator = new Intl.Collator('pt-BR', { usage: 'sort' });
Objects.sort(
(x, y) =>
(intlCollator.compare(x[sort[0]], y[sort[0]])) ||
(intlCollator.compare(x[sort[1]], y[sort[1]])) ||
(intlCollator.compare(x[sort[2]], y[sort[2]]))
);
How would I make the sorting dynamic?
I mean, iterate using variable sort combinations.
For example:
sort = ['function', 'name'];
Or:
sort = ['name'];
You could iterate the keys until a comparing returns a not falsy value.
const
objects = [{ id: 1, name: "Joseph", function: "preacher" }, { id: 2, name: "Ann", function: "singer" }, { id: 3, name: "Miles", function: "preacher" }, { id: 4, name: "Jack", function: "singer" }, { id: 5, name: "Igor", function: "secretary" }],
intlCollator = new Intl.Collator('pt-BR', { usage: 'sort' }),
sort = ['function', 'name'];
objects.sort((a, b) => {
let r;
sort.some(k => r = intlCollator.compare(a[k], b[k]));
return r;
});
console.log(objects);
Since ES10 sort is stable. That means you can first sort using the first key, then sort the second and so on.
const Objects = [
{ "id": 1, "name": "Joseph", function: "preacher"},
{ "id": 2, "name": "Ann", function: "singer"},
{ "id": 3, "name": "Miles", function: "preacher"},
{ "id": 4, "name": "Jack", function: "singer"},
{ "id": 5, "name": "Igor", function: "secretary"}
];
const sort = ['name', 'function'];
const intlCollator = new Intl.Collator('pt-BR', { usage: 'sort' });
sort.forEach(s => {
Objects.sort((l, r) => intlCollator.compare(l[s], r[s]));
});
console.log(Objects);
I have two array objects arrayA and arrayB.
let arrayA = [
{
"category": "red",
"rank": 8,
"phone": 12345
},{
"category": "black",
"rank": 7,
"phone": 12332
}
]
let arrayB = [
{
"category": "red",
"rank": 4,
},{
"category": "black",
"rank": 7,
}
]
return array should be
arrayA = [
{
"category": "red",
"rank": 8,
"phone": 12345
},{
"category": "black",
"rank": 7,
"phone": 12332
}
]
So in the above arrays category is unique for each object. so while comparing if any of the object's rank in arrayA is equal to or greater than respective with the object in arrayB then return the whole arrayA else return nothing.
In the above arrays in category of red, rank of arrayA is greater(rank -> 8) than the rank of arrayB(rank -> 4) in the red category so arrayA need to return.
In case if the in arrayA rank in category "red" is less than the rank of respective in arrayB then return nothing.
I tried some method but filter one is filtering out the object from array which do not satisfied the condition, but I want whole array as it is if any of the some method's condition satisfied in one or more object.
let arrayC = arraA.filter(o1 =>
arrayB.some(o2 =>
{return (o1.category=== o2.category&& o1.rank >= o2.rank)}));
can anybody help here?
If the order is not the same then you can Map to make it more efficient.
let arrayA = [
{
category: "red",
rank: 8,
phone: 12345,
},
{
category: "black",
rank: 7,
phone: 12332,
},
];
let arrayB = [
{
category: "red",
rank: 4,
},
{
category: "black",
rank: 7,
},
];
const map = new Map(arrayB.map((o) => [o.category, o]));
const result = arrayA.some((o) => o.rank >= map.get(o.category).rank) ? arrayA: [];
console.log(result);
You can concatenate the two arrays, and use a reducer.
Included logs so you can easily go through the code yourself.
const mergedArray = arrayA.concat(arrayB)
// We use a reducer to combine the merged Array.
mergedArray.reduce((acc, { category, rank, phone }) => {
console.log(`category: ${category} - rank: ${rank} - phone: ${phone}`)
// First find if the given category exist in accumulator
const foundCategoryObject = acc.find(a => a.category === category)
console.log(`foundCategoryObject: ${JSON.stringify(foundCategoryObject)}`)
// If not found, simply add the found current object to acc and return
if (!foundCategoryObject) return [...acc, { category: category, rank: rank, phone: phone }]
// If not found, check if the later object has higher or lower rank
else {
if (foundCategoryObject.rank >= rank) {
console.log(`"new" object has lower rank. Return original("old") object. (NO Change) ${category}-${rank}-${phone}`)
return acc
}
else {
console.log(`"new" object has higher rank. Return "nothing". Delete the "old" object and return acc. ${category}-${rank}-${phone}`)
return acc.filter(a => a.category !== category)
}
}
}, [])
Looks pretty simple, I have added another case in the example, can you let us know if this is what you were looking for.
I compare the category of both the arrays and then compare rank.
if only 'b' has a higher rank object with same name category, I remove the object from result/
let arrayA = [
{
"category": "red",
"rank": 8,
"phone": 12345
},{
"category": "black",
"rank": 7,
"phone": 12332
},
{
"category": "orange",
"rank": 6,
"phone": 12332
}
]
let arrayB = [
{
"category": "red",
"rank": 4,
},{
"category": "black",
"rank": 7,
},
{
"category": "orange",
"rank": 12,
}
]
// dic had key: category and value as ArrayB objects
let dic = arrayB.reduce((dic,v) => (dic[v.category] = v, dic) , {})
let result = arrayA.filter(a => dic[a.category].rank <= a.rank)
console.log(result)
I want to restructure the current JSON of data as shown below
const data = [
{
"status": "Complete",
"totalToday": 3,
"weekly": 20
},
{
"status": "Pending",
"totalToday": 5,
"weekly": 13
},
{
"status": "Rejected",
"totalToday": 2,
"weekly": 5
}
];
Expected output:
const newData = [
['Status', 'Total Today', 'Weekly'],
['Complete', 3, 20],
['Pending', 5, 13],
['Rejected', 2, 5]
];
You can use Array.forEach()
const data = [{
"status": "Complete",
"totalToday": 3,
"weekly": 20
},
{
"status": "Pending",
"totalToday": 5,
"weekly": 13
},
{
"status": "Rejected",
"totalToday": 2,
"weekly": 5
}
];
let transformedData = []
transformedData.push(Object.keys(data[0]).map(key => {
return key.replace(/([A-Z])/g, ' $1')
.replace(/^./, (str) => str.toUpperCase())
}))
data.forEach(val => transformedData.push(Object.values(val)))
console.log(transformedData)
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
You can simply use a reduce method, in which you iterate over an Array of Object. On the 0 index, you can use Object.keys() to get the key and Object.values for the corresponding values and push it to the accumulator. For else you can iterate Object values and push it to the accumulator acc.
const data = [
{
"status": "Complete",
"totalToday": 3,
"weekly": 20
},
{
"status": "Pending",
"totalToday": 5,
"weekly": 13
},
{
"status": "Rejected",
"totalToday": 2,
"weekly": 5
}
];
const newData = data.reduce((acc, x, idx) => {
if(idx === 0) {
acc.push(Object.keys(x), Object.values(x));
} else {
acc.push(Object.values(x));
}
return acc;
}, [])
console.log(newData);
How can we retrieve name from the json, when array of ids are provided.
[
{
"id": 0,
"name": "salesTransNo"
},
{
"id": 1,
"name": "terminalNo"
},
{
"id": 2,
"name": "salesTransDate"
},
{
"id": 3,
"name": "salesTransTime"
},
{
"id": 4,
"name": "exceptionAmount"
},
{
"id": 5,
"name": "laneNumber"
}
]
I want to retrieve only names into an array from the JSON, when array of id values are given
eg: array of id's : [2,4,5]
Output should be:
["salesTransDate","exceptionAmount","LaneNumber"]
How can we achieve this with Lodash or with JavaScript ?
I used _.find and used _.map to pull only name from the result, but it's only working for single value, if I were to pass an array like [2,4,5] it's not working.
You could filter the objects and then map the wanted property.
var data = [{ id: 0, name: "salesTransNo" }, { id: 1, name: "terminalNo" }, { id: 2, name: "salesTransDate" }, { id: 3, name: "salesTransTime" }, { id: 4, name: "exceptionAmount" }, { id: 5, name: "laneNumber" }],
ids = [2, 4, 5],
result = data
.filter(({ id }) => ids.includes(id))
.map(({ name }) => name);
console.log(result);
Vanilla JS:
var arr = [
{ "id": 0, "name": "salesTransNo" },
{ "id": 1, "name": "terminalNo" },
{ "id": 2, "name": "salesTransDate" },
{ "id": 3, "name": "salesTransTime" },
{ "id": 4, "name": "exceptionAmount" },
{ "id": 5, "name": "laneNumber" }
];
var indexes = arr.map ( function ( d ) { return d.id; });
var id = 4; // Requested arr.id item
var select_name = arr[indexes.indexOf(id)].name;
If you wish to return multiple results, you can build a function like so:
function getNamesFromArr ( list_of_ids ) {
var result = [];
for ( var i = 0; i < list_of_ids.length; i++ ) {
var indexes = arr.map ( function ( d ) { return d.id; });
var select_name = arr[indexes.indexOf(list_of_ids[i])].name;
result.push ( select_name );
}
return result;
}
getNamesFromArr ([ 2, 4, 5 ]); // Returns ["salesTransDate", "exceptionAmount", "laneNumber"]
Note: I had left out error handling for simplicity. Consider catching indexOf() values of -1.
var items = [{
"id": 0,
"name": "salesTransNo"
},
{
"id": 1,
"name": "terminalNo"
},
{
"id": 2,
"name": "salesTransDate"
},
{
"id": 3,
"name": "salesTransTime"
},
{
"id": 4,
"name": "exceptionAmount"
},
{
"id": 5,
"name": "laneNumber"
}
]
var iname = items.filter(items => [2, 4, 5].includes(items.id));
for (var names of iname)
{console.log(names.name);}
You can do that with a lodash's chain using _.keyBy(), _.at(), and _.map():
var data = [{ id: 0, name: "salesTransNo" }, { id: 1, name: "terminalNo" }, { id: 2, name: "salesTransDate" }, { id: 3, name: "salesTransTime" }, { id: 4, name: "exceptionAmount" }, { id: 5, name: "laneNumber" }];
var ids = [2, 4, 5];
var result = _(data)
.keyBy('id') // convert to a dictionary by id
.at(ids) // get the items which id match the id array
.map('name') // pluck the name
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
You can use lodash#intersectionWith, wherein the arguments order must be the collection first, the ids second and the comparator at the end.
var result = _.intersectionWith(data, ids, (a, b) => a.id == b);
var data = [{
id: 0,
name: "salesTransNo"
}, {
id: 1,
name: "terminalNo"
}, {
id: 2,
name: "salesTransDate"
}, {
id: 3,
name: "salesTransTime"
}, {
id: 4,
name: "exceptionAmount"
}, {
id: 5,
name: "laneNumber"
}],
ids = [2, 4, 5];
var result = _.intersectionWith(data, ids, (a, b) => a.id == b);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>