Angular 4 GroupBy Array Data - javascript

I have an array which looks like:
var data = [
{
student: "sam",
English: 80,
Std: 8
},
{
student: "sam",
Maths: 80,
Std: 8
},
{
student: "john",
English: 80,
Std: 8
},
{
student: "john",
Maths: 80,
Std: 8
}
];
and I need to get the total marks irrespective of subject for student sam.
By filtering data array by student name and then looping the filtered data, can get the individual student total marks.
Is there any groupBy function as similar to SQL in Typescript.

This seems like it can be done with a simple reduce method on the array. Reduce will iterate over an array and pass each item into the provided predicate function. Each iteration should return the accumulator obj/array/val.
I wasn't sure what you wanted the data structure to be, but you can control the structure by the inner working of the function you pass to reduce.
studentScores = this.data.reduce((accumulator, item) => {
const key = Object.keys(item)
.filter(k => k !== 'student')
.filter(k => k !== 'Std')[0];
const prevValue = accumulator[item.student] || 0;
const studentName = item.student;
accumulator[studentName] = prevValue + item[key];
return accumulator;
}, {});
I posted a working example in a stackblitz at https://stackblitz.com/edit/angular-xcjzzf

You have to do it using dictionary. Easy way to grouping is used a map.there mark's name is changing so the task is difficult.This is stackblitz link.

Related

Trying to apply filter and reduce on an array to sum only numbers

I'm trying to write a function that will be called with an array that has information on a person such as their name and then age. I need this function to grab all of the numbers only and then return them then add them all together but I'm having trouble figuring out how to combine filter and reduce (if that's what I even need to use to do this in the easiest way?) so if you could help with that I would be thankful.
Maybe it would be easier for me not to use an arrow function but I just learned about them an hour ago and wanted to try them out.
Apologies for any typos/wrong jargon as my dyslexia gets the better of me sometimes.
What I've got so far;
const totalNums = arr => arr.reduce((a,b) => a + b, 0)
An example of what I want it to return when the function is supplied with the array is
{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 },
// returns 92
EDIT
Why isn't the array I'm calling this function with working? Can you provide me a working example without the array being hardcoded like the other answers? - I'm passing in an array to the function. The main objective is to grab any number from the passed in array and add them together with an empty array returning 0.
function totalNums(person) {
person.reduce((a,b) => a + b, 0)
return person.age;
}
console.log(totalNums([]))
The first argument in a reduce callback is the "accumulator" - something that takes the initial value and is then passed into each iteration. The second value is the item that's next in the iteration whether that's a number, a string, an object etc.
In your example you're iterating over an array of objects, so you must perform the sum operation using the age value of each of those objects.
const arr = [
{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 }
];
const total = arr.reduce((acc, obj) => {
return acc + obj.age;
}, 0);
console.log(total);
You can reduce the object array number as below
const objArr = [
{ name: "Clarie", age: 22 },
{ name: "Bobby", age: 30 },
{ name: "Antonio", age: 40 },
];
console.log(objArr.reduce((prev, curr) => prev + curr.age, 0));
If you want to convert the array of object into array containing only ages:
const objArr = [
{ name: 'Clarie', age: 22 },
{ name: 'Bobby', age: 30 },
{ name: 'Antonio', age: 40 },
];
console.log(objArr.map(obj => obj.age));

From array of Object , get array of only matched key value

Suppose I have an array of object:
var students = [{name: 'Nick',achievements: 158,points: 1473}, {name: 'Nick',achievements: '175',points: '16375'},
{name: 'Ramon',achievements: '55',points: '2025'}];
I want to extract points from name Nick only in an array.
Like if (name=='Nick), O/P should be [1473,16375]
I tried:
var arrayPoints = students.map(function (el) {
if(el.name=='Nick'){
return el.points
}
});
But it gives me o/p:
console.log(arrayPoints)
[1473,16375,undefined] o/p
A look to the methods:
Array#map returns a (new) value for each element.
Array#filter returns exactly the element if the return value of the callback is truthy
You could take two steps, one for filtering the items and another to get the values from.
const
students = [{ name: 'Nick', achievements: 158, points: 1473 }, { name: 'Nick', achievements: '175', points: '16375' }, { name: 'Ramon', achievements: '55', points: '2025' }],
arrayPoints = students
.filter(student => student.name === 'Nick')
.map(student => student.points);
console.log(arrayPoints);
If Array#flatMap is implemented, you could take a single loop and filter and return a value.
The empty array has no items and this array is a neutral value which does not turn up in the result array.
const
students = [{ name: 'Nick', achievements: 158, points: 1473 }, { name: 'Nick', achievements: '175', points: '16375' }, { name: 'Ramon', achievements: '55', points: '2025' }],
arrayPoints = students
.flatMap(student => student.name === 'Nick'
? student.points
: []
);
console.log(arrayPoints);
For single loop result without undefined. You could do with Array#reduce
students.reduce(function (acc,el) {
if(el.name=='Nick'){
acc.push(el.points)
}
return acc
},[]);
You can use reduce for that:
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.
So You can use it and check if the name is indeed Nick (el is the currentValue).
if so then push the points to the accumulator (which is arr).
[] represent the initialValue passed to the reduce function.
var arrayPoints = students.reduce((arr, el) =>
(el.name === 'Nick' && arr.push(el.points), arr), [])
You can find more info regarding reduce here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

React - Filter JSON array if key exists [duplicate]

I have an array of objects and I'm wondering the best way to search it. Given the below example how can I search for name = "Joe" and age < 30? Is there anything jQuery can help with or do I have to brute force this search myself?
var names = new Array();
var object = { name : "Joe", age:20, email: "joe#hotmail.com"};
names.push(object);
object = { name : "Mike", age:50, email: "mike#hotmail.com"};
names.push(object);
object = { name : "Joe", age:45, email: "mike#hotmail.com"};
names.push(object);
A modern solution with Array.prototype.filter():
const found_names = names.filter(v => v.name === "Joe" && v.age < 30);
Or if you still use jQuery, you may use jQuery.grep():
var found_names = $.grep(names, function(v) {
return v.name === "Joe" && v.age < 30;
});
You can do this very easily with the [].filter method:
var filterednames = names.filter(function(obj) {
return (obj.name === "Joe") && (obj.age < 30);
});
You can learn more about it on this MDN page.
You could utilize jQuery.filter() function to return elements from a subset of the matching elements.
var names = [
{ name : "Joe", age:20, email: "joe#hotmail.com"},
{ name : "Mike", age:50, email: "mike#hotmail.com"},
{ name : "Joe", age:45, email: "mike#hotmail.com"}
];
var filteredNames = $(names).filter(function( idx ) {
return names[idx].name === "Joe" && names[idx].age < 30;
});
$(filteredNames).each(function(){
$('#output').append(this.name);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"/>
var nameList = [
{name:'x', age:20, email:'x#email.com'},
{name:'y', age:60, email:'y#email.com'},
{name:'Joe', age:22, email:'joe#email.com'},
{name:'Abc', age:40, email:'abc#email.com'}
];
var filteredValue = nameList.filter(function (item) {
return item.name == "Joe" && item.age < 30;
});
//To See Output Result as Array
console.log(JSON.stringify(filteredValue));
You can simply use javascript :)
For those who want to filter from an array of objects using any key:
function filterItems(items, searchVal) {
return items.filter((item) => Object.values(item).includes(searchVal));
}
let data = [
{ "name": "apple", "type": "fruit", "id": 123234 },
{ "name": "cat", "type": "animal", "id": 98989 },
{ "name": "something", "type": "other", "id": 656565 }]
console.log("Filtered by name: ", filterItems(data, "apple"));
console.log("Filtered by type: ", filterItems(data, "animal"));
console.log("Filtered by id: ", filterItems(data, 656565));
filter from an array of the JSON objects:**
var names = [{
name: "Joe",
age: 20,
email: "joe#hotmail.com"
},
{
name: "Mike",
age: 50,
email: "mike#hotmail.com"
},
{
name: "Joe",
age: 45,
email: "mike#hotmail.com"
}
];
const res = _.filter(names, (name) => {
return name.name == "Joe" && name.age < 30;
});
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
So quick question. What if you have two arrays of objects and you would like to 'align' these object arrays so that you can make sure each array's objects are in the order as the other array's? What if you don't know what keys and values any of the objects inside of the arrays contains... Much less what order they're even in?
So you need a 'WildCard Expression' for your [].filter, [].map, etc. How do you get a wild card expression?
var jux = (function(){
'use strict';
function wildExp(obj){
var keysCrude = Object.keys(obj),
keysA = ('a["' + keysCrude.join('"], a["') + '"]').split(', '),
keysB = ('b["' + keysCrude.join('"], b["') + '"]').split(', '),
keys = [].concat(keysA, keysB)
.sort(function(a, b){ return a.substring(1, a.length) > b.substring(1, b.length); });
var exp = keys.join('').split(']b').join('] > b').split(']a').join('] || a');
return exp;
}
return {
sort: wildExp
};
})();
var sortKeys = {
k: 'v',
key: 'val',
n: 'p',
name: 'param'
};
var objArray = [
{
k: 'z',
key: 'g',
n: 'a',
name: 'b'
},
{
k: 'y',
key: 'h',
n: 'b',
name: 't'
},
{
k: 'x',
key: 'o',
n: 'a',
name: 'c'
}
];
var exp = jux.sort(sortKeys);
console.log('#juxSort Expression:', exp);
console.log('#juxSort:', objArray.sort(function(a, b){
return eval(exp);
}));
You can also use this function over an iteration for each object to create a better collective expression for all of the keys in each of your objects, and then filter your array that way.
This is a small snippet from the API Juxtapose which I have almost complete, which does this, object equality with exemptions, object unities, and array condensation. If these are things you need or want for your project please comment and I'll make the lib accessible sooner than later.
Hope this helps! Happy coding :)
The most straightforward and readable approach will be the usage of native javascript filter method.
Native javaScript filter takes a declarative approach in filtering array elements. Since it is a method defined on Array.prototype, it iterates on a provided array and invokes a callback on it. This callback, which acts as our filtering function, takes three parameters:
element — the current item in the array being iterated over
index — the index or location of the current element in the array that is being iterated over
array — the original array that the filter method was applied on
Let’s use this filter method in an example. Note that the filter can be applied on any sort of array. In this example, we are going to filter an array of objects based on an object property.
An example of filtering an array of objects based on object properties could look something like this:
// Please do not hate me for bashing on pizza and burgers.
// and FYI, I totally made up the healthMetric param :)
let foods = [
{ type: "pizza", healthMetric: 25 },
{ type: "burger", healthMetric: 10 },
{ type: "salad", healthMetric: 60 },
{ type: "apple", healthMetric: 82 }
];
let isHealthy = food => food.healthMetric >= 50;
const result = foods.filter(isHealthy);
console.log(result.map(food => food.type));
// Result: ['salad', 'apple']
To learn more about filtering arrays in functions and yo build your own filtering, check out this article:
https://medium.com/better-programming/build-your-own-filter-e88ba0dcbfae

How can i find out the last entered object in an array of objects, where similar objects can be entered multiple times

Suppose,
i have an object with properties, details : {"name","id"} , now there is an array that holds collection of details. now suppose , an object with {name:max, id:55} is pushed in the array more than once. how do i find out the last entered {name:max,id:55} from that array using TypeScript .
You can do it with pure JavaScript and lastIndexOf:
const myArray = [{
name: "max",
id: 55
}, {
name: "john",
id: 13
}, {
name: "susan",
id: "123"
}, {
name: "max",
id: 55
}];
const lastEntered = (name, id) => {
var matches = myArray.filter(e => e.name == name && e.id == id);
return matches.length - 1;
}
console.log(lastEntered("max", 55));
Array is last in first out data structure.
So the last in element will occupy the element with the largest index.
So you may get the element by array[array.length-1]
You can use reduce to change the array to an object, where the key is a value from the object, and the value is the last index of that key.
const details = [{ name: 'max', id: 55 }];
const detailsMap = details.reduce((acc, person, index) => {
acc[person.id] = index;
return acc;
}, {});
const lastIndexOfMax = detailsMap[55];
Here we set the id from the detail object to the key (because I assumed that each id is unique). When we enter that key into the details map, it returns to use the index of the array where that id is last located.

How do I transform an array to hold data based on a value in the data?

I have seen some questions that might look similar but none is the solution in my case. I want to regroup and recreate my array the way that it is arranged or grouped based on one of my values(age). I want to have all data of the same "age" in one place. So here is my sample array:
[
{
"age": 15,
"person": {
name: 'John',
hobby: 'ski'
},
},
{
"age": 23,
"person": {
name: 'Suzi',
hobby: 'golf'
},
},
{
"age": 23,
"person": {
name: 'Joe',
hobby: 'books'
}
},{
"age": 25,
"person": {
name: 'Rosi',
hobby: 'books'
}
},{
"age": 15,
"person": {
name: 'Gary',
hobby: 'books'
}
},
{
"age": 23,
"person": {
name: 'Kane',
hobby: 'books'
}
}
]
And I need to have an array that kind of have age as a key and person as value, so each key could have multiple values meaning the value will kind of be an array itself.
I have read this and this questions and many more but they were not exactly the same.
I feel like I need to use reduce to count duplicate ages and then filter it based on that but how do I get the values of those ages?
EIDT:
Sorry for not being clear:
This is what I need:
{
23: [
{ name: 'Suzi', hoby: 'golf' },
{ name: 'Joe', hobby: 'books'}
],
15: [
{ name: 'Gary', hobby: 'books' }
] ,
.
.
.
}
You're actually going to want to reduce, not filter. Filtering an Array means to remove elements and place the kept elements into a new container. Reducing an array means to transform it into a single value in a new container. Mapping an array means to transform every value in place to a new container. Since you want to change how the data is represented that's a Reduction, from one form to another more condensed form.
Assume your Array of values is stored in let people = [...]
let peopleByAge = people.reduce(function (accumulator, value, index, array){
// The first time through accumulator is the passed extra Object after this function
// See the MDN for Array.prototype.reduce() for more information
if (accumulator[value.age] == undefined){
accumulator[value.age] = [];
}
accumulator[value.age].push(value);
return accumulator
}, {})
console.log(peopleByAge) // { 23: [{ age: 23, name: ..., hobby: ...}, ...], 13: [...], ...}
You can find the MDN article for Array#reduce() here
Thanks to #RobertMennell who patiently answered me and I voted as answer. But I just wanted to write my version which MDN had a great example of. It is a longer version assuming the people is the array name:
const groupedByvalue = 'age';
const groupedArray = people;
const groupBy = (peopleArray, value) => {
return peopleArray.reduce((acc, obj) => {
const key = obj[value];
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(obj);
return acc;
}, {});
}
console.log(groupBy(groupedArray,groupedByvalue));
Update:
More polished using ternary operator:
const groupedByvalue = 'age';
const groupedArray = people;
const groupBy = (peopleArray, value) => {
return peopleArray.reduce((acc, obj) => {
const key = obj[value];
(!acc[key]) ? (acc[key] = []) : (acc[key].push(obj))
return acc;
}, {});
}
console.log(groupBy(groupedArray,groupedByvalue));

Categories

Resources