How to group array and count values - arrays

I have an array that I want to group according to type then count the number of instances for every unique status.
Here is my array:
const array = [
{ type: 'A', number: 2, status:'Approved', year: '2020' },
{ type: 'A', number: 3, status:'Approved', year: '2020' },
{ type: 'A', number: 3, status:'Disapproved', year: '2020' },
{ type: 'A', number: 6, status:'Disapproved', year: '2020' },
{ type: 'A', number: 5, status:'Processing', year: '2020' },
{ type: 'B', number: 8, status:'Processing', year: '2020' },
{ type: 'B', number: 2, status:'Approved', year: '2020' },
{ type: 'B', number: 2, status:'Disapproved', year: '2020' },
]
Here is my desired array:
const desiredArray = [
{ type: 'A', Approved:5, Disapproved: 9, Processing: 13, year: '2020' },
{ type: 'B', Approved:2, Disapproved: 2, year: '2020' },
]

With help from other online friends, this worked perfectly:
const reducedObject = array.reduce((rv,x) =>{
if(!rv[x.type]) {
rv[x.type] = {
type: x.type,
Approved: 0,
Disapproved: 0,
Processing: 0,
year: x.year
}
}
rv[x.type][x.status]++;
return rv;
}, {});
const desiredArray = Object.values(reducedObject);

Another answer:
var array = [
{ Id: "001", qty: 1 },
{ Id: "002", qty: 2 },
{ Id: "001", qty: 2 },
{ Id: "003", qty: 4 }
];
var result = [];
array.reduce(function(res, value) {
if (!res[value.Id]) {
res[value.Id] = { Id: value.Id, qty: 0 };
result.push(res[value.Id])
}
res[value.Id].qty += value.qty;
return res;
}, {});
console.log(result)

Related

Mapping through nested arrays in es6 javascript

I have a simple array that I want to group it's objects by date so I used this function
const groupedDates= Object.entries(
items.reduce((acc, { product, price, type, date }) => {
if (!acc[date]) {
acc[date] = [];
}
acc[date].push({ product, price, type date });
return acc;
}, {})
).map(([date, items]) => ({ date, items }));
the array
const items = [
{
id: 1,
product: "milk",
price: 10,
type: "drink"
date: "01/01/2022",
},
{
id: 2,
product: "coca",
price: 11,
type: "drink"
date: "01/01/2022",
},
{
id: 3,
product: "pepsi",
price: 20,
type: "drink"
date: "01/01/2024",
},
{
id: 4,
product: "carrots",
price: 30,
type: "food",
date: "01/01/2023",
},
];
I got this result
{
0: [
date: 01/01/2022,
items : [
0 : {
id: 1,
product: "milk",
price: 10,
type: "drink"
date: "01/01/2022"
}
1 : {
id: 2,
product: "coca",
price: 11,
type: "drink"
date: "01/01/2022",
}
],
1: [
date: "01/01/2024",
items : [
0 : {
id: 3,
product: "pepsi",
price: 20,
type: "drink"
date: "01/01/2024",
}
],
2: [
date: "01/01/2023",
items: [
0:{
id: 4,
product: "carrots",
price: 30,
type: "food",
date: "01/01/2023"
}
]
]
}
Issue:
I cannot seem to figure out how to access items1 when it exists.
What I have tried
is the map below but it only returns the first level of items which is 0 and if I do items1 it returns an error because not all arrays have a second item.
{groupedDates.map((obj) => (
{obj.items[0].product}))}
UPDATE
I'd also like to get the total for each date so I can have a card that has the Date + The total + each item and it's individual price. After getting some help from #Nick, I've managed to output the date, the item and it's price, now I'm still missing the total price for the date.
You need to iterate the items in each obj to get the list of products:
const items = [
{ id: 1, product: "milk", price: 10, type: "drink", date: "01/01/2022" },
{ id: 2, product: "coca", price: 11, type: "drink", date: "01/01/2022" },
{ id: 3, product: "pepsi", price: 20, type: "drink", date: "01/01/2024" },
{ id: 4, product: "carrots", price: 30, type: "food", date: "01/01/2023" },
];
const groupedDates = Object.entries(
items.reduce((acc, { product, price, type, date }) => {
if (!acc[date]) {
acc[date] = [];
}
acc[date].push({ product, price, type, date });
return acc;
}, {})
).map(([date, items]) => ({ date, items }));
const allProducts = groupedDates.map((obj) => obj.items.map(i => i.product))
console.log(allProducts)
const totalsByDate = groupedDates.map(({ date, items }) => (
{ [date] : items.reduce((acc, item) => acc + item.price, 0) }
))
console.log(totalsByDate)
.as-console-wrapper { max-height:100% !important; top 0 }
Note I would make groupedDates an object with its keys being the dates; that will make looking up data for a given date much easier. For example:
const items = [
{ id: 1, product: "milk", price: 10, type: "drink", date: "01/01/2022" },
{ id: 2, product: "coca", price: 11, type: "drink", date: "01/01/2022" },
{ id: 3, product: "pepsi", price: 20, type: "drink", date: "01/01/2024" },
{ id: 4, product: "carrots", price: 30, type: "food", date: "01/01/2023" },
];
const groupedDates = items.reduce((acc, { date, ...rest }) => {
acc[date] = (acc[date] || []).concat({ ...rest })
return acc;
}, {})
console.log(groupedDates)
const allProducts = Object.values(groupedDates)
.flatMap(arr => arr.map(obj => obj.product))
console.log(allProducts)
const totalsByDate = Object.entries(groupedDates).map(([ date, items ]) => (
{ [date] : items.reduce((acc, item) => acc + item.price, 0) }
))
console.log(totalsByDate)
.as-console-wrapper { max-height:100% !important; top 0; }

How to filter multiple objects from a list objects by a property array?

I have a object array in which each object contain an id and a name and a separate array contains a set of ids. I want to filter first array based on the second array.
const data= [
{
id: 1,
name: 'name1'
},
{
id: 2,
name: 'name2'
},
{
id: 3,
name: 'name3'
},
{
id: 4,
name: 'name4'
}
];
const array = [1,3,4];
const expectedResult= [
{
id: 1,
name: 'name1'
},
{
id: 3,
name: 'name3'
},
{
id: 4,
name: 'name4'
}
];
Use .filter and .includes
const data= [
{
id: 1,
name: 'name1'
},
{
id: 2,
name: 'name2'
},
{
id: 3,
name: 'name3'
},
{
id: 4,
name: 'name4'
}
];
const array = [1, 3, 4]
const result = data.filter((item) => {
//gives us items that passes a condition
return array.includes(item.id)
})
console.log(result)

How to filter array based on id in angularJS

i have multiple data for one id , i want filter my data like this
$scope.mpArray =[
{ Id: 1, Name: Madhu, Address: Upal },
{ Id: 1, Name: Chandu, Address: Upal },
{ Id: 2, Name: Srinu, Address: Kphb },
{ Id: 2, Name: Vijay, Address: kphb },
{ Id: 3, Name: Ajay, Address: Banglore },
{ Id: 3, Name: Narsi, Address: Banglore },
{ Id: 3, Name: Peter, Address: Banglore },
];
i want to filter my array like this
var FilterArray = [
{ Id: 1,Madhu, Chandu},
{ Id: 2, Srinu, Vijay},
{ Id: 3, Ajay, Narsi, Peter},
];
At first you need to change your FilterArray to
[
{
"Id": 1,
"Name": [
"Madhu",
"Chandu"
]
},
{
"Id": 2,
"Name": [
"Srinu",
"Vijay"
]
},
{
"Id": 3,
"Name": [
"Ajay",
"Narsi",
"Peter"
]
}
]
Notice that name is an array. The FilterArray of your question
var FilterArray = [
{ Id: 1,Madhu, Chandu},
{ Id: 2, Srinu, Vijay},
{ Id: 3, Ajay, Narsi, Peter},
];
Do not contain a valid JSON object inside the array so you need to change the structure to the one where add a new key Name in the JSON object of FilterArray as like the first structure above. Then the below code works great.
$(document).ready(function(){
var myArray =[
{ Id: 1, Name: "Madhu", Address: "Upal" },
{ Id: 1, Name: "Chandu", Address: "Upal" },
{ Id: 2, Name: "Srinu", Address: "Kphb" },
{ Id: 2, Name: "Vijay", Address: "kphb" },
{ Id: 3, Name: "Ajay", Address: "Banglore" },
{ Id: 3, Name: "Narsi", Address: "Banglore" },
{ Id: 3, Name: "Peter", Address: "Banglore" },
];
var FilterArray = [];
var matched;
for(var i=0;i<myArray.length; i++){
matched = false;
var myArrayId = myArray[i].Id;
for(var j=0; j<FilterArray.length; j++){
var FilterArrayId = FilterArray[j].Id;
if(myArrayId === FilterArrayId){
matched = true;
FilterArray[j].Name.push(myArray[i].Name);
// no need to loop further
break;
}
}
if(!matched){
var obj = {
'Id' : myArrayId,
'Name' : [myArray[i].Name],
}
FilterArray.push(obj);
}
}
console.log(FilterArray);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
try this
var mpArray =[
{ Id: 1, Name: 'Madhu', Address: 'Upal' },
{ Id: 1, Name: 'Chandu', Address: 'Upal' },
{ Id: 2, Name: 'Srinu', Address: 'Kphb' },
{ Id: 2, Name: 'Vijay', Address: 'kphb' },
{ Id: 3, Name: 'Ajay', Address: 'Banglore' },
{ Id: 3, Name: 'Narsi', Address: 'Banglore' },
{ Id: 3, Name: 'Peter', Address: 'Banglore' },
];
var filterObject = {};
mpArray.forEach(function (item) {
if (!filterObject[item.Id]) {
filterObject[item.Id] = [];
}
filterObject[item.Id].push(item.Name);
});
console.log(filterObject);
$scope.mpArray =[
{ Id: 1, Name: 'Madhu', Address: 'Upal' },
{ Id: 1, Name: 'Chandu', Address: 'Upal' },
{ Id: 2, Name: 'Srinu', Address: 'Kphb' },
{ Id: 2, Name: 'Vijay', Address: 'kphb' },
{ Id: 3, Name: 'Ajay', Address: 'Banglore' },
{ Id: 3, Name: 'Narsi', Address: 'Banglore' },
{ Id: 3, Name: 'Peter', Address: 'Banglore' },
];
var FilterArray = [];
var FilteredArrayIds=[];
$scope.mpArray.forEach(
function(detailObj) {
if(FilteredArrayIds.indexOf(detailObj.Id)==-1)
return FilteredArrayIds.push(detailObj.Id);
});
for(var i=0; i<FilteredArrayIds.length;i++)
{
var result = $scope.mpArray.filter(function( obj ) {
return obj.Id == FilteredArrayIds[i];
});
var rsltNames = result.map(function(obj){
return obj.Name;
})
var filteredObj ={
id:FilteredArrayIds[i]+',' +rsltNames.join()
}
FilterArray.push(filteredObj);
}
console.log(filteredObj)

Protractor promise produces array that overrides previous values [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 7 years ago.
I have angular ui grid that I am trying to get values from its cells. Here is my list in table
id name
1 AUSTRIA
2 BELGIUM
3 BULGARIA
4 CROATIA
5 CZECH REPUBLIC
This is code I run:
element(by.id('grid1')).all(by.repeater('(rowRenderIndex, row) in rowContainer.renderedRows track by $index')).then(function (items) {
for (var i = 0; i < items.length; i++) {
var country = <any>{}; //typescript code
self.gridTestUtils.dataCell('grid1', i, 0).getText().then(
function (valueId) {
country.id = valueId
});
self.gridTestUtils.dataCell('grid1', i, 1).getText().then(
function (valueName) {
country.name = valueName;
self.countryList.push(country)
console.log(self.countryList)
});
}
});
And this is result
[ { id: 1, name: 'AUSTRIA' }]
[ { id: 1, name: 'BELGIUM' },
{ id: 1, name: 'BELGIUM' }]
[ { id: 1, name: 'BULGARIA' },
{ id: 1, name: 'BULGARIA' },
{ id: 1, name: 'BULGARIA' } ]
[ { id: 1, name: 'CROATIA' },
{ id: 1, name: 'CROATIA' },
{ id: 1, name: 'CROATIA' },
{ id: 1, name: 'CROATIA' } ]
[ { id: 1, name: 'CZECH REPUBLIC' },
{ id: 1, name: 'CZECH REPUBLIC' },
{ id: 1, name: 'CZECH REPUBLIC' },
{ id: 1, name: 'CZECH REPUBLIC' },
{ id: 1, name: 'CZECH REPUBLIC' } ]
I expect result would look like:
[ { id: 1, name: 'AUSTRIA' }]
[ { id: 1, name: 'AUSTRIA' },
{ id: 1, name: 'BELGIUM' }]
[ { id: 1, name: 'AUSTRIA' },
{ id: 1, name: 'BELGIUM' },
{ id: 1, name: 'BULGARIA' } ]
[ { id: 1, name: 'AUSTRIA' },
{ id: 1, name: 'BELGIUM' },
{ id: 1, name: 'BULGARIA' },
{ id: 1, name: 'CROATIA' } ]
[ { id: 1, name: 'AUSTRIA' },
{ id: 1, name: 'BELGIUM' },
{ id: 1, name: 'BULGARIA' },
{ id: 1, name: 'CROATIA' },
{ id: 1, name: 'CZECH REPUBLIC' } ]
What is wrong with my code? What should I do that I have expected array
The problem is that i in your loop changes as the loops goes through, and in your async calls you are using i and getting a promise, but it's only a reference, so at the time the promises get resolved, the will have the reference to the variable with the last value of the loop. A workaround is to create an IIFE:
element(by.id('grid1')).all(by.repeater('(rowRenderIndex, row) in rowContainer.renderedRows track by $index')).then(function (items) {
for (var i = 0; i < items.length; i++) {
var country = <any>{}; //typescript code
(function (i, country) {
self.gridTestUtils.dataCell('grid1', i, 0).getText().then(function (valueId) {
country.id = valueId;
});
self.gridTestUtils.dataCell('grid1', i, 1).getText().then(function (valueName) {
country.name = valueName;
self.countryList.push(country)
console.log(self.countryList)
});
})(i, country);
}
});

angularjs : I have one form it has many fields some of them carrying array to display dropdown. is it wise that we should provider?

I have one form which has 10 to 12 fields which contains dropdown and multi select drop down. I want before my controller function gets called all the fields should filled up. I tried something like this :
var app = angular.module('app', []);
app.config(function ($provide) {
var transactionType = [
{ id: 0, type: 'card', value: 'card' },
{ id: 1, type: 'cash', value: 'cash' },
{ id: 2, type: 'other', value: 'other' }
];
var friends = [
{ id: 0, name: 'A', value: 'A' },
{ id: 1, name: 'B', value: 'B' },
{ id: 2, name: 'C', value: 'C' },
{ id: 3, name: 'D', value: 'D' }
];
var currency = [
{ id: 0, currency: 'USD', value: 'USD' },
{ id: 0, currency: 'INR', value: 'INR' },
{ id: 0, currency: 'EUR', value: 'EUR' },
];
$provide.value('TransactionType', transactionType);
$provide.value('Friends', friends);
$provide.value('Currency', currency);
});
app.controller('MainCtrl', function ($scope, TransactionType, Friends, Currency) {
});
Is this the right way considering that may be in future I have to use http service to get array from DB and to populate on dropdown list?
I'd use a specific type of provider called a Factory instead. If you use promises in your factory when switch to http services you'd only need to change your factory code - the rest of your application will work without code changes!
angular.module('myApp')
.factory('Friend', function ($q) {
return {
list: function() {
var deferred = $q.defer();
deferred.resolve([
{ id: 0, name: 'A', value: 'A' },
{ id: 1, name: 'B', value: 'B' },
{ id: 2, name: 'C', value: 'C' },
{ id: 3, name: 'D', value: 'D' }
]);
return deferred.promise;
}
};
});

Resources