There are two aspects to this question: parsing and sorting.
- You can use regular expressions to validate custom data types.
- You can use
cin to analyze the data.
First: understand that you can’t know what type your users are entering until you get it all ~ for example: consider a list of usernames:
728278243 390349346 495045594 elizabeth
Therefore, it is better not to assume that it is better to know about the input data (this can lead to user frustration), but instead they prefer to consider everything as a potential string. Store all the source data as strings so you can output them in the same format as the input. you can use, say, an enumerated type to switch inside a sorting comparator, or consider using mutliset/multimap . here you will be building an ordered set. therefore there is no need to sort. NB: the difficulty of constructing an ordered set of N elements or, for one sort on N unsorted list elements, is roughly equivalent to ~> NlogN
For your task in your hand, this does not matter much, but in fact, depending on how this list is used, this or that approach will be much more suitable in terms of performance.
If you have already used similar std::vector , then std::multimap should not be too scary. Clearly, this is an associated array of key-value pairs. multi here means that it can store several elements with the same key (which is here, you want).
In this example, I use the regex boost library to define some funky input data types.
(e.g. sudo apt-get install libboost-regex1.46-dev )
This regular expression may seem cryptic, but there are many examples on i / web for almost all possible patterns. [NB: C ++ 11 regex is a pretty significant replacement for re-expressing boost. that is: boost regex should be compatible with the new version of C ++ 11]
blah.cpp:
#include <iostream> #include <sstream> #include <string> #include <list> #include <map> #include <set> #include <boost/regex.hpp> //NB: GNU gcc added *experimental support for regular expressions in TR1 v 4.3.0. // compile with: -std=c++0x using namespace std; using namespace boost; //some example input data-types (perhaps notably missing a date!) const regex re_char("[^0-9]", regex_constants::extended); //non numeric chars const regex re_digit("[[:digit:]]+", regex_constants::extended); //a string of only digits in range [0..9] ~ie: Z+ const regex re_xdigit("0[xX][[:xdigit:]]+", regex_constants::extended); //support hex iff starts with '0x' or '0X' const regex re_float("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?", regex_constants::extended); //all kinds of numbers int main(int argc, char** argv) { int i, countc=0; double d; string str; int element_count; do { cout << "how many elements will there be? "; if (cin >> element_count) break; cin.clear(); cin >> str; cout << "\033[A\033[2K" << flush; } while(13); cin.ignore(128,'\n'); multimap<double, string> list_num; multimap<double, string> list_fp; //NB: below, by way of example, construction using the 'greater<int>' comparison class achieves _descending_ order multimap<int, string, greater<int> > list_int; list<string> list_str; for (int next=0; next < element_count; next++) { cout << "\033[A\033[2K" << flush; cout << "enter next element in list ["<< next+1 << "/" << element_count << "] : "; getline (cin,str); if (regex_match(str, re_xdigit)) { //see all about manipulators here: //http://www.cplusplus.com/reference/iostream/istream/operator%3E%3E/ stringstream(str) >> hex >> i; list_int.insert(pair<int, string>(i, str)); list_num.insert(pair<double, string>(i, str)); } else if (regex_match(str, re_digit)) { stringstream(str) >> i; list_int.insert(pair<int, string>(i, str)); list_num.insert(pair<double, string>(i, str)); } else if (regex_match(str, re_float)) { stringstream(str) >> d; list_fp.insert(pair<double, string>(d, str)); list_num.insert(pair<double, string>(d, str)); } if (regex_match(str, re_char)) countc++; list_str.push_back(str); } cout << "\033[A\033[2K" << flush; cout << "input: unsorted list:" << endl; for (list<string>::iterator it=list_str.begin(); it!=list_str.end(); it++) cout << *it << endl; if (list_int.size() == element_count) { cout << endl << "output: sorted list of Z+ types:" << endl; for (multimap<int, string>::iterator it=list_int.begin() ; it != list_int.end(); it++ ) cout << (*it).second << endl; } else if (list_fp.size() == element_count) { cout << endl << "output: sorted list of fp types:" << endl; for (multimap<double, string>::iterator it=list_fp.begin() ; it != list_fp.end(); it++ ) cout << (*it).second << endl; } else if (list_num.size() == element_count) { cout << endl << "output: sorted list of numeric types:" << endl; for (multimap<double, string>::iterator it=list_num.begin() ; it != list_num.end(); it++ ) cout << (*it).second << endl; } else //output as sorted strings ~but in _descending_ order, using reverse iterator, by way of example { list_str.sort(); //but best to use list_str.sort(greater<string>()); with forward iterators cout << endl << "output: sorted list of " << (countc == element_count ? "non numeric char" : "string") << " types:" << endl; for (list<string>::reverse_iterator it=list_str.rbegin(); it!=list_str.rend(); ++it) cout << *it << endl; } return 0; }
The example was compiled and run on Ubuntu. Command Line Material:
$ $ lsb_release -d Description: Ubuntu 11.10 $ g++ --version g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 $ g++ --pedantic -oblah blah.cpp -lboost_regex $ ./blah input: unsorted list: 4.77 2.0e+2 -.3 11 0x10 output: sorted list of numeric types: -.3 4.77 11 0x10 2.0e+2 $
NB: This is a sample code:
- There are many optimizations you can do here. You clearly do not need as many
stl containers as I use. - I do not strictly understand this kind of direction (but I will show a couple of ways in which this can be achieved).
- It may also be convenient to encapsulate type-specific functions in C ++ objects; have a base class and then derived classes for each type you want to support ~, but is this homework right? -Therefore, it is probably not worth going overboard, then;)