Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 29, 2014 Sorting structs? | ||||
---|---|---|---|---|
| ||||
Hello everybody. I'm trying to learn D by solving simple exercises. The current exercise: read names and grades of students, then print the names of students in descending order of their grades. In C++, I would define a Student struct, overload the operators: bool operator<(const Student&, const Student&) std::istream& operator>>(std::istream&, Student&) Then I'd store the Students in let's say a std::vector, sort it in reverse, then print it accordingly. But I don't know how to do things in D. I'm reading Cehreli's book, so far I've only finished its first trinity (just before struct). I would appreciate it if you explained your approach and gave source code illustrating it. Thanks! |
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Boomerang | Am 29.01.2014 10:33, schrieb Boomerang:
> Hello everybody. I'm trying to learn D by solving simple
> exercises.
>
> The current exercise: read names and grades of students, then
> print the names of students in descending order of their grades.
>
> In C++, I would define a Student struct, overload the operators:
> bool operator<(const Student&, const Student&)
> std::istream& operator>>(std::istream&, Student&)
>
> Then I'd store the Students in let's say a std::vector, sort it
> in reverse, then print it accordingly.
>
> But I don't know how to do things in D. I'm reading Cehreli's
> book, so far I've only finished its first trinity (just before
> struct).
>
> I would appreciate it if you explained your approach and gave
> source code illustrating it. Thanks!
You can either overload the compare operator for the struct
struct bla
{
int i;
int opCmp(ref const(bla) rh)
{
if(this.i < rh.i)
return -1;
if(this.i > rh.i)
return 1;
return 0;
}
}
or you could just pass a different compare less expression to sort
bla[] arrayToSort;
sort!"a.i < b.i"(arrayToSort);
You can also pass a lambda or any function as compare less function to sort:
sort!((a,b){return a.i < b.i;})(arrayToSort);
Kind Regards
Benjamin Thaut
|
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Boomerang | On Wednesday, 29 January 2014 at 09:33:50 UTC, Boomerang wrote: > I would appreciate it if you explained your approach and gave > source code illustrating it. Thanks! This can be solved without sorting in reverse or overloading anything in C++ (with a predicate version of sort() algorithm), and in D too. Take a look at this code: http://dpaste.dzfl.pl/2d0dd6f953dc the std.algorithm.sort() takes an optional predicate (as a template argument) to resolve the order of elements. In this case, it is specified as an anonymous function (a,b) => a.grade > b.grade You could alternatively specify it as a string: sort!"a.grade > b.grade"(students); or like this: sort!q{a.grade > b.grade}(students); |
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | It's also worth noting that you can avoid passing structs into predicate function by value, and instead pass them by reference: sort!((ref const a, ref const b) => a.grade > b.grade)(students); This is useful for "heavy" structs to save on performance. E.g. in this case, Student.sizeof is 24 bytes on 64 bit machine. Passing by reference will only need to copy 16 bytes (i.e. size of two pointers), whereas passing by value will incur copying 48 bytes (two structs). |
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | Thanks for the help so far. My current code is here: http://dpaste.dzfl.pl/b9acff399649 Are there problems with my code, or do you have suggestions to improve it? |
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Boomerang | Also sorry for double posting but I'm confused how the sorting works when we only specify to be sorted by grade. I think in C++, disregarding other data members can lead to loss of data in things such as std::set. |
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Boomerang | On Wednesday, 29 January 2014 at 10:30:06 UTC, Boomerang wrote: I'll paste here with comments: import std.algorithm; import std.stdio; import std.array; void main() { struct Student { string name; float grade; } Student[] studs; writeln("Enter student data. Reading stops when student name is empty."); while (true) { // Calls to readf() may throw an exception // if user inputs invalid data. // You may want to consider accounting // for that. typeof(Student.name) name; write("Student name: "); readf("%s\n", &name); // Don't burden users with typing STOP :) if (name.empty) break; typeof(Student.grade) grade; write("Student grade: "); import std.exception; import std.conv : ConvException; // EXAMPLE: catch all ConvExceptions // to persuade user to input a number :) while(collectException!ConvException(readf("%s\n", &grade))) { // Conversion failed but there's still data in // stdin. We get rid of it: readln; write("Please enter NUMERIC student grade: "); } // Create Student only when necessary // (a good compiler will optimize that // to avoid copying): studs ~= Student(name, grade); } // Use anonymous function with explicit // parameter storage class specifier; // Also Use UFCS studs.sort!((ref const a, ref const b) => a.grade > b.grade); // You can omit type name in foreach; // also it's worth using ref const to avoid // unnecessary copies foreach (ref const s; studs) writeln(s.name); // Or avoid foreach altogether: studs.map!((ref const s) => writeln(s.name)); } > Also sorry for double posting but I'm confused how the sorting works when we only specify to be sorted by grade. I think in C++, disregarding other data members can lead to loss of data in things such as std::set. Yes and no. In fact, std::set is by default instantiated with an std::less predicate. But std::set is intended to store unique elements. So if you try to insert an element that std::set already considers to exist (it uses the predicate to determine that), it doesn't insert it. But you must understand that despite being generic, algorithms and containers still serve particular purposes. You wouldn't store students in a set unless you had some way to uniquely identify them :) |
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | On Wednesday, 29 January 2014 at 11:24:54 UTC, Stanislav Blinov wrote:
>
> // Or avoid foreach altogether:
> studs.map!((ref const s) => writeln(s.name));
> }
Did you test this one? std.algorithm.map is lazy.
|
January 29, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tobias Pankrath | On Wednesday, 29 January 2014 at 12:44:37 UTC, Tobias Pankrath wrote:
> On Wednesday, 29 January 2014 at 11:24:54 UTC, Stanislav Blinov wrote:
>>
>> // Or avoid foreach altogether:
>> studs.map!((ref const s) => writeln(s.name));
>> }
> Did you test this one? std.algorithm.map is lazy.
Ah yes, sorry, my bad. I forgot to remove foreach during testing and assumed it worked. Facepalm m)
|
January 30, 2014 Re: Sorting structs? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stanislav Blinov | On Wednesday, 29 January 2014 at 11:24:54 UTC, Stanislav Blinov wrote:
> On Wednesday, 29 January 2014 at 10:30:06 UTC, Boomerang wrote:
> // also it's worth using ref const to avoid
> // unnecessary copies
I am new to D.
Why should someone use "ref const" instead of "in"?
|
Copyright © 1999-2021 by the D Language Foundation