I have a text file with content like this: Bill, 89 Alex, 64 Dan, 29
, which represents the names of some students and their note.
I want to sort them ascending by note, and my idea is to make an integer for every name, for example: int dan = 29;
so further I can sort them, but I have no idea how to assign a integer for this names from the text file.
Hope you can help because is the first time I make a little bit more complex program. Thank you!
问题:
回答1:
The problem here is that in C++ (as in C) you have to define all your variables in compile time, i.e. when you write your code. And in your example you have text file with arbitrary count of lines, so you dont really know about it's content when you write code. This is why you cannot have very own variable for every line of your file.
So, if you need to store information about every line of your file, you can do this. First, you define format in which your information (i.e. string with name + integer) will be stored. This is the place where you most likely will need struct
or something like that. struct
and class
are the way to agregate diffirent variables in one structure (essentially, they are more than just that, but that's not the point at the moment). If you wrote smth like
struct Data {
std::string name;
int ratio;
};
that means that you just defined data type called Data, that have fields "name" and "ratio". So you can use it like this:
Data d;
d.name = "Ben";
d.ratio = 42;
After this, you need some entity that can let you to store many of this Data entries. For example, you could use arrays. Imagine you will use static array here:
const std::size_t lineCount = getLineCount();
Data data_array[lineCount]; //Will not compile, since you cannot use variables as static arrays's size
for( std::size_t i = 0; i < lineCount; ++i ) {
data_array[i].name = readName();
data_array[i].ratio = readRatio();
}
Problem here, as you can see, is that you cannot know line count of your textfile when you write code. So you can you dynamic arrays with this code:
const std::size_t lineCount = getLineCount();
Data* data_array = new Data[lineCount];
for( std::size_t i = 0; i < lineCount; ++i ) {
data_array[i].name = readName();
data_array[i].ratio = readRatio();
}
delete[] data_array;
This will work, provided you somehow managed to know count of lines if your file before actual work is done, which is not the point usually.
Also raw dynamic arrays are not really nice to use because of that new/delete function pair you have to worry about. So, here in action come classes called containers from Standart Template Library. This classes provides you way to just insert data in it, and operate with this data in many ways. This is the classes "map", "unordered_map", "multimap", "vector" and others from former answers. Easiest of them to understand is vector, and you can read about it here. Others (say'd, map) should fit better to your task.
Finally, to sort array (or container) of such data, you can use functions called algorithms from Standart Template Library. They provide generic way to operate on data in the way you need. You can read more here.
Not sure I need to say more here, explore links, continue your studies, good luck!
回答2:
There is probably a more clever way to do this but since you're a beginner here's what I suggest:
Use a std::multimap<int, std::string>
to serve as a lookup table for a name (stored as a std::string
) given the int
note. You want a std::multimap
instead of a std::map
in case some names have the same int
value. Separately, store all the numbers in a std::vector<int>
and call std::sort()
to sort the std::vector<int>
. Now they're sorted, and you can use std::multimap::find()
to look up the name(s) associated with each int
value.
回答3:
Use std::unordered_map<string, int>
.
//Usage:
std::unordered_map<string, int> content;
//open file;
while(/*not end of file*/){
std::string name;
int mark;
file>>name>>mark;
name.erase(name.end()-1);
content[name]=mark;
}
//close file;
回答4:
struct name_and_mark{
std::string name;
int mark;
bool operator<(name_and_mark &second){
return mark<second.mark;
}
};
std::istream& operator>>(std::istream &stream, name_and_mark &data){
stream>>data.name>>data.mark;
data.name.erase(data.name.end()-1);
return stream;
}
std::forward_list<name_and_mark> content;
//open file;
while(/*not end of file*/){
name_and_mark temp;
file>>temp;
content.push_front(temp);
}
//close file;
content.sort();
//To check it out:
std::ostream& operator<<(std::ostream &stream, name_and_mark &data){
stream<<data.name<<", "<<data.mark<<'\n';
return stream;
}
for(auto &i:content)
std::cout<<i;