ordering array of objects using JavaScript - javascript

I have the following array of objects which orders the list. The problem is that the ordering is wrong because the OrderId property is not unique across all headings. The OrderId starts from 1 for each heading, hence the problem.
Please help!
Many thanks
// Class
var Item = function(orderId, forename, surname, heading) {
this.OrderId = orderId;
this.Forename = forename;
this.Surname = surname;
this.Heading = heading;
};
// Creation of objects
var obj1 = new Item(1, "James", "Smith", "Heading1");
var obj2 = new Item(2, "Tracey", "Janes", "heading1");
var obj3 = new Item(3, "Sarah", "Cann", "Heading1");
var obj4 = new Item(1, "Matt", "Bars", "Heading2");
var obj4 = new Item(2, "Alex", "Magi", "Heading2");
// Add to array
tempArray.push(obj1);
tempArray.push(obj2);
tempArray.push(obj3);
tempArray.push(obj4);
// Sort array
tempArray.sort(function(a, b) {
var a1 = a.OrderId, b1 = b.OrderId;
if (a1 == b1) return 0;
return a1 > b1 ? 1 : -1;
});
// Render array to screen - order by OrderId
for(var i = 0; i < tempArray.length; i++) {
console.log(tempArray[i].Heading);
console.log(tempArray[i].Forename + " " + tempArray[i].Surname);
}
The output I need:
Heading 1
James Smith
Tracey Janes
Sarah Cann
Heading 2
Matt Bars
Alex Magi
Because the OrderId is not unique across I get the following issue
Heading 1
James Smith
Matt Bars
Alex Magi
Tracey Janes
Sarah Cann
Heading 2

If you want to default order by id then you can add toString method to your Object and return the id as string as this is used by .sort:
var Item = function(orderId, forename, surname, heading) {
this.OrderId = orderId;
this.Forename = forename;
this.Surname = surname;
this.Heading = heading;
};
Item.prototype.toString=function(){
return this.OrderId+"";
};
// create a bunch of Items
tmpArray.sort();// done, it's sorted by id now
If you want to sort it on certain key(s) then you can pass a sort function to tmpArray.sort
function sortItems(arr,keys){
var len=keys.length;
arr.sort(function(a,b){
var i=0;
while(a[keys[i]]===b[keys[i]]&&i<len){
i++;
}
return i===len?0:(a[keys[i]]>b[keys[i]])?1:-1;
}
};
// sort by Surname then by Forename (if 2 items have same Surname)
sortItems(tmpArray,["Surname", "Forename"]);
Looking at your question again I see it's not the sorting that is the problem but the grouping. here is a function that would implement grouping for you.
var Item = function(orderId, forename, surname, heading) {
this.OrderId = orderId;
this.Forename = forename;
this.Surname = surname;
this.Heading = heading;
};
// Creation of objects
var obj1 = new Item(1, "James", "Smith", "Heading1");
var obj2 = new Item(2, "Tracey", "Janes", "Heading1");
var obj3 = new Item(3, "Sarah", "Cann", "Heading1");
var obj4 = new Item(1, "Matt", "Bars", "Heading2");
var obj5 = new Item(2, "Alex", "Magi", "Heading2");
var tempArray=[];
tempArray.push(obj1);
tempArray.push(obj2);
tempArray.push(obj3);
tempArray.push(obj4);
tempArray.push(obj5);
function sortItems(arr,keys){
var len=keys.length;
arr.sort(function(a,b){
var i=0;
while(a[keys[i]]===b[keys[i]]&&i<len){
i++;
}
return i===len?0:(a[keys[i]]>b[keys[i]])?1:-1;
});
};
// sort on Heading
sortItems(tempArray,["Heading","Forename","Surname"]);
function groupBy(arr,key){
var i=0,ret={};
for(i=0;i<arr.length;i++){
if(!ret[arr[i][key]]){
ret[arr[i][key]]=[];
}
ret[arr[i][key]].push(arr[i]);
}
return ret;
};
var grouped=groupBy(tempArray,"Heading");
var key="",i =0,ret=[];
// If any code in your page adds to Object.prototype then this breaks
// like Object.prototype.mySmartFuncion since mySmartFunciton will show
// up as key in for key in anyObject
for(key in grouped){
ret.push(grouped[key][0].Heading);
for(i=0;i<grouped[key].length;i++){
ret.push("\t"+grouped[key][i].Forename + grouped[key][i].Surname);
}
}
console.log(ret.join("\n"));

Related

How to use variable in JSON object value while creating an object dynamically?

I'm trying to create an array of object dynamically using for loop. The values for the key value pair of this object are fed from different arrays. So how can I create the array of object dynamically using for loop? I tried the following block of code but it was not working.
var anObj = [];
var charectors = ['Iron Man', 'Hulk', 'Thor']
var actors = ['Robert Downey, Jr', 'Mark Ruffalo', 'Chris Hemsworth']
for(let i=0; i<charectors.length; i++){
anObj[i] = {
charector : charectors[i],
actor : actors[i]
}
}
The above code throws an error as I was expecting the array of object as
[
{
"charector":"Iron Man",
"actor":"Robert Downey, Jr"
},
{
"charector":"Hulk",
"actor":"Mark Ruffalo"
},
{
"charector":"Thor",
"actor":"Chris Hemsworth"
}
]
You can also use map
var anObj = [];
var charectors = ["Iron Man", "Hulk", "Thor"];
var actors = ["Robert Downey, Jr", "Mark Ruffalo", "Chris Hemsworth"];
const result = actors.map((actor, i) => ({ charector: charectors[i], actor: actors[i] }));
console.log(result)
with for...of loop
var anObj = [];
var charectors = ["Iron Man", "Hulk", "Thor"];
var actors = ["Robert Downey, Jr", "Mark Ruffalo", "Chris Hemsworth"];
const result = [];
for (let [i, actor] of actors.entries()) {
result.push({
charector: charectors[i],
actor: actors[i],
});
}
console.log(result);
Use : instead of = in your for loop.
Basic object properties assignement
var anObj = [];
var charectors = ['Iron Man', 'Hulk', 'Thor']
var actors = ['Robert Downey, Jr', 'Mark Ruffalo', 'Chris Hemsworth']
for(let i=0; i<charectors.length; i++){
anObj[i] = {
charector : charectors[i],
actor : actors[i]
}
}
Push the values into the array using
anObj.push({
charector: charectors[i],
actor: actor[i]
})
You have two errors:
the assignment separator inside the braces is the colon, not the
equal sign;
the name of the second source array is actors, not actor.
var anObj = [];
var charectors = ['Iron Man', 'Hulk', 'Thor']
var actors = ['Robert Downey, Jr', 'Mark Ruffalo', 'Chris Hemsworth']
for(let i=0; i<charectors.length; i++){
anObj[i] = {
charector : charectors[i],
actor : actors[i]
}
}
console.log(anObj);

Using an array inside a constructor using Javascript

I've been trying to find a way to correctly define an array as one of the constructor values. Let's say we have a student and we need to have an array with his grades and then using the array we need to get an average from the student's grades. Sadly, I only found some threads addressing this in other programming languages. This is what I thought would work:
function student(name, surname, number, grades) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = [];
this.average = function(grades) {
var sum = 0;
for(var i = 0; i < grades.length; i++) {
sum + = grades[i];}
var average = sum / grades.length;
return average;
}
}
And then
var student1 = new student("Peter","Cat",14444,[2,3,4]);
console.log(student1);
Unfortunately, it shows my grades array as blank and I can't see if my average function is working properly. Which part(s) should I change so that I would actually have some values in the grades array?
Thank you.
You have a couple things messed up. If you are going to pass the grades array in as an argument, then you need to set grades with this:
this.grades = grades;
Also in the average function you need to refer to grades with this.grades not just grades. This will allow you to add more grades later and still get the correct average. You could also consider making the grades optional by defining the constructor with something like:
function student(name, surname, number, grades =[])
Then if you don't pass in a value, an empty array will be waiting for you.
In the end you might have something like:
function student(name, surname, number, grades = []) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
this.average = function() {
return this.grades.reduce((a, c) => a + c, 0) / this.grades.length
}
}
var student1 = new student("Peter", "Cat", 14444, [2, 3, 4]);
console.log("Average: ", student1.average())
// add another grade:
student1.grades.push(6)
console.log("New Average: ", student1.average() )
You can solve same problem by using ES6, in your code, you are initializing this.grade=[] with an empty array inside function so further processing of average will be done on empty array only. For good practice, function parameters should be assigned with a default value, so that if mistakenly we do not pass an array as an argument then the function parameter will use the default value. Attaching code snippet for easy understanding in ES6.
class std{
constructor(name, surname, number, grades = []) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
}
average() {
if(this.grades.length !== 0){
return this.grades.reduce((previous, current) => previous + current, 0) /
this.grades.length
} else { return "no grades mentioned"; }
}
}
var student1 = new std("Peter", "Cat", 14444, [1, 3, 4]);
console.log("Average: ", student1.average());
//add new student
var student2 = new std("Prasanna", "sasne", 14444);
console.log(student2);
//student2.grades.push(7)
//console.log("New Average: ", student2.average() )
You're already passing grades into the student() function, so you don't need to pass it in to the student.average function (as the inner function will already have access to the outer function parameter). Because of this, you also don't need to set this.grades = [].
Also, sum + = grades[i] should be sum += grades[i].
Simply fixing this error, then omitting passing grades into the inner function will correctly show the average, as can be seen in the following:
function student(name, surname, number, grades) {
this.name = name;
this.surname = surname;
this.number = number;
this.average = function() {
var sum = 0;
for (var i = 0; i < grades.length; i++) {
sum += grades[i];
}
var average = sum / grades.length;
return average;
}
}
var student1 = new student("Peter", "Cat", 14444, [2, 3, 4]);
console.log(student1.average());
Your initialization of the variable is an empty array.
this.grades = [];
Should be
this.grades = grades;
However, I recommend that you study some javascript ES6 / ECMAScript 2015 and use classes.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
class Student {
constructor(grades) {
//... Other code
this.grades = grades;
}
}
you can use this line :
function student(name, surname, number, grades){ }
instead of this:
function student(name, surname, number, grades = [ ]){ }
function student(name, surname, number, grades) {
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
this.average = function() {
return this.grades.reduce((a, c) => a + c, 0) / this.grades.length
}
}
var student1 = new student("Peter", "Cat", 14444, [2, 3, 4]);
console.log("Average: ", student1.average())
// add another grade:
student1.grades.push(6)
console.log("New Average: ", student1.average() )
We can use the Object Method to store the Average value:
function Student(name, surname, number, grades = [])
{
this.name = name;
this.surname = surname;
this.number = number;
this.grades = grades;
//Method to calculate the Average
this.average = function()
{
if(this.grades.length !==0)
{
//Return the Average Calculation
return this.grades.reduce((previous, current) => previous + current, 0) / this.grades.length
}
else
{
//This will return if grades not provided
return "No Grades Mentioned"
}
}
}
//With Grades
var student1 = new Student("Srinivasan", "Raja", 1635, [22,43,67,89,90]);
console.log(student1, "Average: "+ student1.average());
//Without Grades
var student1 = new Student("Denny", "Lawrence", 1635);
console.log(student1, "Average: "+ student1.average());

JavaScript basics: array or arrays

I'm trying to learn JavaScript and am going through an exercise where I'm creating a grocery list that populates with a food, quantity, and cost. I cannot seem to pass in multiple variables or make an array of arrays. I tried some other options like "new Object" but I can't get anything off the ground. Give me a clue?
var groceryList = function(food, quantity, price) {
var theItem = [food, quantity, price]
var theList = new Array();
theList.push(theItem)
}
myList = new groceryList("cookie", 2, 1.00)
console.log(myList)
Use this
var groceryList = function(food, quantity, price) {
var theItem = [food, quantity, price]
var theList = new Array();
theList.push(theItem);
return theList;
}
myList = new groceryList("cookie", 2, 1.00)
console.log(myList)
If you want to use objects, then you need to change your thinking a little bit. When you create an object with new then the constructor gets called.
function GroceryList(food, quantity, price) {
this.food = food;
this.quantity = quantity;
this.price = price;
}
GroceryList.prototype.toString = function() {
return this.food + (this.quantity).toString() + (this.price).toString();
}
// lazy array syntax
var GroceryListPool = [];
// popular the array list pool
var list1 = new GroceryList("Butter", 2, 3.999);
GroceryListPool.push(list1);
To iterate the GroceryListPool array:
for(var i = 0; i < GroceryListPool.length; i++) {
var list = GroceryListPool[i];
// list is an object of type GroceryList
// technically it is not a "type", but you know what I mean.
alert(list);
}
That's not even really a Constructor, yet. Check this out.
function groceryList(food, quantity, price){
this.items = {};
if(food !== undefined){
this.items[food] = {quantity:quantity, price:price, total:quantity*price};
}
this.addItem = function(food, quantity, price){
this.items[food] = {quantity:quantity, price:price, total:quantity*price};
}
this.getFood(food){
return this.items[food];
}
this.getQuantity = function(food){
return this.items[food].quantity;
}
this.getTotal = function(food){
return this.items[food].total;
}
this.getItemsByPrice(low, high){
var r = {}, t = this.items;
for(var i in t){
var f = t[i], p = f.price;
if(p >= low && p <= high){
r[i] = f;
}
}
return r;
}
}
var groc = new groceryList('potato', 4, 0.89);
groc.addItem('orange', 10, 1);
console.log(groc.getQuantity('potato'));
console.log(groc.getTotal('orange'));
console.log(groc.getFood('orange').price);
// same as
console.log(groc.getPrice('orange'));
// or
console.log(groc.items.orange.price);
groc.addItem('pear', 200, 0.75);
console.log(groc.getItemsByPrice(0.25, 0.99)); // should be Object with 'potato' and 'pear'

Javascript Object - Use a variable that is defined in the object before it's creation

How can I achieve this?
var people = Array();
people.push({
name: "John",
height_in_cm : 190,
height_in_inches : this.height_in_cm * 0.39
});
This is not working. It's obvious that the object is not yet created. Are there any tricks on getting this to work?
You could just declare the object first and then push it:
var people = [];
var obj = {
name: "John",
height_in_cm : 190
};
obj.height_in_inches = obj.height_in_cm * .39;
people.push(obj);
Depending on your case you could also create a "Person" object/class:
var person = (function personModule() {
function Person(props) {
this.name = props.name;
this.height_in_cm = props.height_in_cm;
this.height_in_inches = this.height_in_cm * .39;
}
Person.prototype = {...}; // public methods if necessary
return function(props) {
return new Person(props);
}
}());
var people = [];
people.push(person({ name: 'John', height_in_cm: 190 }));
console.log(people[0].height_in_inches); //=> 74.1

Alter and Assign Object Without Side Effects

I currently have the following code:
var myArray = [];
var myElement = {
id: 0,
value: 0
}
myElement.id = 0;
myElement.value = 1;
myArray[0] = myElement;
myElement.id = 2;
myElement.value = 3;
myArray[1] = myElement;
The problem is that when I change the value of id and value for my second element, the values also change in the first element. Is there a way that I can keep adding new elements without it changing the value of the previously inserted values in the array?
Try this instead:
var myArray = [];
myArray.push({ id: 0, value: 1 });
myArray.push({ id: 2, value: 3 });
or will this not work for your situation?
This is a textbook case for a constructor function:
var myArray = [];
function myElement(id, value){
this.id = id
this.value = value
}
myArray[0] = new myElement(0,1)
myArray[1] = new myElement(2,3)
// or myArray.push(new myElement(1, 1))
You either need to keep creating new objects, or clone the existing one. See What is the most efficient way to deep clone an object in JavaScript? for how to clone.
That's because object values are passed by reference. You can clone the object like this:
var myArray = [];
var myElement = {
id: 0,
value: 0
}
myElement.id =0;
myElement.value=1;
myArray[0] = myElement;
var obj = {};
obj = clone(myElement);
obj.id = 2;
obj.value = 3;
myArray[1] = obj;
function clone(obj){
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = new obj.constructor();
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
console.log(myArray[0]);
console.log(myArray[1]);
Result:
- id: 0
- value: 1
- id: 2
- value: 3
If you're using jQuery, you can use extend
myElement.id =0;
myElement.value=1;
myArray[0] = $.extend({}, myElement);
myElement.id = 2;
myElement.value = 3;
myArray[1] = $.extend({}, myElement);
Objects are passed by reference.. To create a new object, I follow this approach..
//Template code for object creation.
function myElement(id, value) {
this.id = id;
this.value = value;
}
var myArray = [];
//instantiate myEle
var myEle = new myElement(0, 0);
//store myEle
myArray[0] = myEle;
//Now create a new object & store it
myEle = new myElement(0, 1);
myArray[1] = myEle;
You will have the same object two times in your array, because object values are passed by reference. You have to create a new object like this
myElement.id = 244;
myElement.value = 3556;
myArray[0] = $.extend({}, myElement); //for shallow copy or
myArray[0] = $.extend(true, {}, myElement); // for deep copy
or
myArray.push({ id: 24, value: 246 });

Categories