How do I conditionally create an array of class parameters from an array in D? - d

Say I have an associative array that contains a bunch of class instances. I want to find an idiomatic D way of creating an array (or range) containing properties that belong to class instances in the array that mean some boolean criteria.
See the example below, in this case I would want to create an array or range containing the age of students that are in the fifth grade.
I know how to do this with loops and conditionals, but if there is a built-in function or idiomatic way of doing this in D, that would be super helpful.
import std.stdio;
class Student {
private:
uint grade;
uint age;
uint year;
public:
this(uint g, uint a, uint y) {
grade = g;
age = a;
year = y;
}
uint getAge() {
return age;
}
uint getGrade() {
return grade;
}
uint getYear() {
return year;
}
}
void main() {
Student[uint] classroom;
Student s1 = new Student(1, 5, 2);
Student s2 = new Student(2, 6, 1);
Student s3 = new Student(3, 7, 2);
Student s4 = new Student(4, 8, 9);
classroom[1] = s1;
classroom[2] = s1;
classroom[3] = s1;
classroom[4] = s1;
// I want to generate an array or range here containing the age of students who are in the X'th grade
}

All you need is little bit of functional programming with the help of the std.algorithm module:
import std.stdio;
import std.algorithm, std.array;
class Student {
private:
uint grade;
uint age;
uint year;
public:
this(uint g, uint a, uint y) {
grade = g;
age = a;
year = y;
}
uint getAge() {
return age;
}
uint getGrade() {
return grade;
}
uint getYear() {
return year;
}
}
void main() {
Student[uint] classroom;
Student s1 = new Student(1, 5, 2);
Student s2 = new Student(2, 6, 1);
Student s3 = new Student(3, 7, 2);
Student s4 = new Student(4, 8, 9);
classroom[1] = s1;
classroom[2] = s2;
classroom[3] = s3;
classroom[4] = s4;
classroom[5] = new Student(3, 8, 3);
// I want to generate an array or range here containing the age of students who are in the X'th grade
uint grd = 3;
auto ages = classroom.values
.filter!(student => student.getGrade() == grd)
.map!(student => student.getAge());
writeln(ages);
uint[] arr = ages.array; // if you need to turn the range into an array
writeln(arr); // prints the same as above
}

std.algorithm has your back:
import std.algorithm, std.array;
auto kids = classroom.values
.filter!(student => student.grade == 5)
.array;
If you want to do this for every grade at once, you need to sort and then chunkBy, something like:
classroom.values
.sort!((x, y) => x.grade < y.grade)
.chunkBy((x, y) => x.grade == y.grade)
Which gives you a range of [ranges of students with the same grade].

Related

Overloading operator+ to add 2 class objects. "C++ expression must be an unscoped integer or enum type" error [duplicate]

This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 9 months ago.
I have a Student class which has dynamic int array marks and int variable marksCount. I am trying to overload operator+ to sum 2 Student* objects. It is supposed only to sum their marks.
For example, when adding 2 students (Student* objects) with marks { 2, 3, 4 } + { 1, 5, 2 }, I must have an output of Student* with marks { 3, 8, 6 }.
But my solution throws C++ expression must be an unscoped integer or enum type exception
on
Student* s = s1 + s2; line.
I have already read similar question and answers but unfortunately I haven't become with solution to my problem. Maybe there is something I don't know about how operator+ works?
#include <iostream>
using namespace std;
class Student
{
private:
int* marks;
int marksCount;
public:
Student(int* marks, int marksCount)
{
this->marks = marks;
this->marksCount = marksCount;
}
Student* operator+(Student* st)
{
int* marks = new int[5];
for (int i = 0; i < 5; i++)
{
marks[i] = this->marks[i] + st->getMarks()[i];
}
Student* s = new Student(marks, 5);
return s;
}
int* getMarks()
{
return marks;
}
void setMarks(int* marks, int SIZE)
{
for (int i = 0; i < SIZE; i++)
{
this->marks[i] = marks[i];
}
}
int getMarksCount()
{
return marksCount;
}
void setMarksCount(int count)
{
marksCount = count;
}
static void printMarks(Student* s1)
{
for (int i = 0; i < s1->getMarksCount(); i++)
{
cout << s1->getMarks()[i];
}
}
};
int main()
{
const int SIZE = 5;
int* marks1 = new int[SIZE] { 2, 3, 5, 4, 1 };
int* marks2 = new int[SIZE] { 4, 2, 3, 1, 2 };
Student* s1 = new Student(marks1, SIZE);
Student* s2 = new Student(marks2, SIZE);
Student* s = s1 + s2;
Student::printMarks(s1);
}
You don't need to use new or pointers here
Student* s1 = new Student(marks1, SIZE);
Student* s2 = new Student(marks2, SIZE);
Student* s = s1 + s2;
so instead
Student s1{marks1, SIZE};
Student s2{marks2, SIZE};
Student s = s1 + s2;
Similarly I would change all your int* to std::vector<int> and basically remove all of the new calls in your entire code.

How do you make an object as a parameter for a function c++

I am trying to make an object as a parameter for my add() function in this code:
class EnterInfo
{
protected:
string name;
int age;
string birthmonth;
public:
EnterInfo()
{
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
public:
CourseInfo()
{
}
CourseInfo(string t)
{
title = t;
}
void add()
{
}
};
int main()
{
EnterInfo s1;
CourseInfo c1;
s1 = EnterInfo("Sand", 20, "Jan");
c1 = CourseInfo(" x Records");
}
I want the add() function to gather all the data from the object "s1" and compact it into an array that I can access later. I could add, remove, or edit the data moving forward or even maybe make a new object "c2" which contains "y records" with the same s1 values ("sand", 20, "Jan"), however, I have no idea how to implement this in code.
c1.add(s1); // assume s1 (EnterInfo): Sand 20 Jan
c1.add(s2); // assume s2 (EnterInfo): Paul 23 Aug
this is the code I want to work with. I don't know how to make it work though. The end game would be this
c1.print();
output:
x records
Sand 20 Jan
Paul 23 Aug
create a vector of EnterInfo objects and put it in CourceInfo class. The code below does what you need:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class EnterInfo
{
public:
string name;
int age;
string birthmonth;
EnterInfo()
{
name = "";
age = 0;
birthmonth = "";
}
EnterInfo(string n, int a, string b)
{
name = n;
age = a;
birthmonth = b;
}
};
class CourseInfo
{
protected:
string title;
vector<EnterInfo> info_vec;
public:
CourseInfo()
{
title = "";
}
CourseInfo(string t)
{
title = t;
}
void add(const EnterInfo enterInfo)
{
this->info_vec.push_back(enterInfo);
}
void print() {
cout << this->title << endl;
for (const auto& it : this->info_vec) {
cout << it.name << " " << it.age << " " << it.birthmonth << endl;
}
}
};
int main()
{
EnterInfo s1("Sand", 20, "Jan");
EnterInfo s2("Arash", 21, "Feb");
CourseInfo c1(" x Records");
c1.add(s1);
c1.add(s2);
c1.print();
}
Side notes:
1- It's better to assign default values to the members of your class in the constructor.
2- I changed the access level of your EnterIndo members into public in order to use them in add function but the standard way is to set them to private and create getters and setters for them.
Research about std::vector and get/setters if you are not familiar with them.

default value for a pointer parameter

I'm trying to create a class for employees, and have a problem with its constructor.
My class looks like that (please note the name parameter which is char* type):
class Employee {
int id;
char * name ;
float salary;
int hours;
int extra;
public:
//constructor
Employee(int, char *, float, int, int);
//Getters and Setters:
void setId(int a) { id = a; }
int getId() { return id; }
void setName(char * c) { name = c; }
char * getName() { return name; }
void setSalary(float f) { salary = f; }
float getSalary() { return salary; }
void setHours(int h) { hours = h; }
int getHours() { return hours; }
void setExtra(int e) { extra = e; }
int getExtra() { return extra; }
};
I built a constructor and I want it to have default parameters, and I don't know how to deal with the name parameter to have a default of let's say "unknown".
This is the constructor:
Employee::Employee(int i = 123456789, char * na, float sal = 30, int ho = 45, int ex = 10)
{
id = i;
name = na;
salary = sal;
hours = ho;
extra = ex;
}
You can use a character array, and initialise the array to point to the first element of the array. You can store the array for example as a static member:
// in the class definition
inline static char default_name[] = "unknown";
// in argument list of the constructor
... char * na = default_name, ...
Although, you may want to consider whether it makes sense for name to be pointer to non-const. Perhaps a pointer to const would suffice. In such case, you could initialise it to point to the literal "unknown" directly.
A cleaner version
class Employee {
int id = 0;
char *name = nullptr;
float salary = 0.0;
int hours = 0;
int extra = 0;
And you don't need to have constructors, this depends on the case, but you get the idea that by initializing the variables on the definition you reduce the inconsistency of having multiples constructors for example

Get summary for multiple class fields in Java8 using map reduce technique

Below is Student class definition :
class Student{
String name;
int sub1;
int sub2;
int sub3;
// etc...etc...
}
I have list of all students.
Requirement is to get average of sub1, sub2 and sub3. And also get min mark and max mark in any subject for any student.
Below is the code for sub1:
IntSummaryStatistics sub1Summary = students.stream().collect(Collectors.summarizingInt(s -> s.sub1));
Is it possible to do with single expression or I will have to create IntSummaryStatisticsfor each subject and compare each lowest and highest subj value?
Thanks in advance
Try following :
List<Student> students = Arrays.asList(Student.create("A", 60, 55, 35),
Student.create("B", 40, 65, 75),
Student.create("C", 70, 45, 95));
Map<String, IntSummaryStatistics> subjectsSummary = new HashMap<String, IntSummaryStatistics>();
Map<String, List<Integer>> subjectMarks = new HashMap<String, List<Integer>>();
List<Integer> sub1Marks = new ArrayList<>();
List<Integer> sub2Marks = new ArrayList<>();
List<Integer> sub3Marks = new ArrayList<>();
// Input : Student
// Output : Map(Key=SubjectName, Value= List of Marks for students)
Function<Student, Map<String, List<Integer>>> toSubjectsMap = (s) -> {
sub1Marks.add(s.getSub1());
sub2Marks.add(s.getSub2());
sub3Marks.add(s.getSub3());
subjectMarks.put("Sub1", sub1Marks);
subjectMarks.put("Sub2", sub2Marks);
subjectMarks.put("Sub3", sub3Marks);
return subjectMarks;
};
//Function to generate summary stats from the list of integers/marks
Function<List<Integer>, IntSummaryStatistics> generateStatsFunc = (listOfMarks) -> {
return listOfMarks.stream().collect(Collectors.summarizingInt(marks->marks));
};
// 1. Students are mapped to generate Map for subject-->List of Marks
// 2. Doing flatMap on the generate Map to get the Keys from the map(list of subjects)
// 3. Collecting the Keys(Subject Names) of Map to Map(Key=SubjectName,Value=IntSummaryStats for Subject)
students.stream().map(toSubjectsMap).flatMap(subMap -> subMap.keySet().stream())
.collect(() -> subjectsSummary/* Initial Value of Map */, (summary, key) -> {
// Generate the stats from the list of marks for the subject
IntSummaryStatistics st = generateStatsFunc.apply(subjectMarks.get(key));
//Adding the stats for each Subject into the result Summary
summary.put(key, st);
} , (summary1, summary2) -> {
//merging the two maps
summary1.putAll(summary2);
});
System.out.println(subjectsSummary);
and Student class as follows :
class Student {
String name;
int sub1;
int sub2;
int sub3;
static Student create(String name, int sub1, int sub2, int sub3) {
// validation
return new Student(name, sub1, sub2, sub3);
}
public String getName() {
return name;
}
public int getSub1() {
return sub1;
}
public int getSub2() {
return sub2;
}
public int getSub3() {
return sub3;
}
private Student(String name, int sub1, int sub2, int sub3) {
this.name = name;
this.sub1 = sub1;
this.sub2 = sub2;
this.sub3 = sub3;
}
#Override
public String toString() {
return name;
}
}

Passing class objects into function parameters c++

I have read several of the previously asked questions on this topic, but can't seem to find the answer I'm looking for. When I run the program I receive no errors, but I get a lot of garbage data. I know it's because I'm not passing the parameters right, but I'm new to c++ and specifically how to use pointers correctly. To make it simple: I am passing an employee object through PrintCheck(), which calls the CalcSalary() function, which must use GetHours() and GetWage() to access member data to do calculations and return the correct salary. Would appreciate any explanations as to why I am generating garbage data!
I have a class:
class Employee
{
private:
int employeeNumber;
string name;
string streetAddress;
string phoneNumber;
double hourlyWage;
double hoursWorkedperWeek;
public:
Employee(void);
Employee(int, string, string, string, double, double);
int GetEmployeeNum() const;
void SetEmployeeNum(int);
string GetName() const;
void SetName(string);
string GetAddress() const;
void SetAddress(string);
string GetPhone() const;
void SetPhone(string);
double GetWage() const;
void SetWage(double);
double GetHours() const;
void SetHours(double);
double CalcPay(double, double);
};
I also have a function that needs to interact with the class:
void PrintCheck(Employee&);
My main function looks like:
void main()
{
Employee joe(1, "Joe Blo", "125 Cool St.", "555 555 5555", 10.00, 45); //create employee 1
Employee jane(2, "Jane Doe", "521 Dumb St.", "1 800 555 5555", 12.50, 30); //create employee 2
PrintCheck(joe); //print check
}
The printcheck function looks like:
void PrintCheck(Employee& a)
{
cout << "Pay to the order of " << a.GetName() << "...................................";
cout << a.CalcPay(a.GetWage(), a.GetHours()) << endl;
cout << "Hours worked: " << a.GetHours() << endl;
cout << "Hourly wage: " << a.GetWage() << endl;
}
Calcpay function is:
double Employee::CalcPay(double h, double w)
{
double salary = 0;
int OT = 40;
double timeandahalf = 1.5;
double STATE = .075;
double FED = .20;
if (h > OT) // overtime
{
salary = h * (w * timeandahalf); // calc time and a half
salary = salary * STATE; // calc state deductions
salary = salary * FED; // calc federal deductions
}
else
{
salary = h * w; // calc salary
salary = salary * STATE; // calc state deductions
salary = salary * FED; // calc federal deductions
}
cout.setf(ios::fixed);
cout.setf(ios::showpoint);
cout.precision(PRECISION);
return salary;
}
My "get" functions all follow this pattern:
int Employee::GetEmployeeNum() const
{
return employeeNumber;
}
My expected output would be:
Pay to the order of: Joe Blo............ $salary.
Hours worked: $hours.
Hourly wage: $wage.
What I got:
Pay to the order of: ........................ 128509280503000000000000000000000000000.00 (this number is long, but I didn't feel like typing them all)
Hours worked: -9723636237 (same, just tons of bs numbers)
Hourly wage: (the exact same number as above)
My class constructor:
Employee::Employee(int en, string n, string a, string p, double w, double h)
{
int employeeNumber = en;
string name = n;
string streetAddress = a;
string phoneNumber = p;
double hourlyWage = w;
double hoursWorkedperWeek = h;
}
Employee::Employee()
{
}
Your Employee::Employee(int en, string n, string a, string p, double w, double h) is declaring new local variables inside it and therefore shadowing the member variables inside your class. So in reality, you never properly initialized any of its members during construction.
The following should correct that problem:
Employee::Employee(int en, string n, string a, string p, double w, double h)
: employeeNumber ( en ),
name ( n ),
streetAddress ( a ),
phoneNumber ( p ),
hourlyWage ( w ),
hoursWorkedperWeek ( h )
{
}
This is the error
Employee::Employee(int en, string n, string a, string p, double w, double h)
{
int employeeNumber = en;
string name = n;
string streetAddress = a;
string phoneNumber = p;
double hourlyWage = w;
double hoursWorkedperWeek = h;
}
it should be
Employee::Employee(int en, string n, string a, string p, double w, double h)
{
employeeNumber = en;
name = n;
streetAddress = a;
phoneNumber = p;
hourlyWage = w;
hoursWorkedperWeek = h;
}
or even better it should be as in greatwolf's answer.
The error in your version is that you've declared variables in your constructor with exactly the same names as the members of your class. These variables hide your class members, so your constructor does not initialise your class. So you get garbage.