Why are the iterators not compatible? - c++

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <iomanip>
using namespace std;
vector<string>::iterator findString(vector<string> word, string x)
{
auto beg = word.begin();
for ( ; beg != word.end() && x != *beg; beg++);
return beg;
}
vector<int>::iterator convert(vector<string>::iterator &t, vector<string> &word, vector<int> &amount)
{
vector<int>::iterator count = amount.begin();
vector<string>::iterator beg = word.begin();
for (; beg != word.end() && beg != t; count++, beg++);
return count;
}
int main()
{
vector<string> word;
vector<int> amount;
string x;
cout << "Please enter words list:" << endl;
cin >> x;
word.push_back(x);
amount.push_back(1);
while (cin >> x)
{
vector<string>::iterator t = findString(word, x);
if (t != word.end()) //A: Error happens in this line.
{
vector<int>::iterator i = convert(t,word,amount);
(*i) ++;
}
else
{
word.push_back(x);
amount.push_back(1);
}
}
for (auto r : word)
cout << setw(4) << r;
cout << endl;
for (auto r : amount)
cout << setw(4) << r;
cout << endl;
return 0;
}
In this program I want to count the number of each word input.
I wrote a conversion function from string iterator to int iterator. But it still doesn't work and says the iterators are not compatible. Is there something wrong? Moreover, I'm confused why iterators can't be converted into the corresponding integers. And why there is 'ptrdiff_t', wouldn't it be easier if it's just 'int'?
It's the first time I use this website. And I'd be grateful if someone can answer my questions. Thanks.
-It's a run-time error, after inputting two strings. Debug assertion failed. File: vector, line 248. Expression: vector iterators incompatible. I ran it on VS2015.
-Error happens in line A.
I understand finally. Thanks everyone. Thank you so much and wish y'all a good day!

Your error doesn't have anything to do with strings or ints or conversions. It's because you're creating a new copy of vector<string> word every time you call findString, and so its returned iterator is an iterator of a different vector (it's an iterator into a copy). You have:
vector<string>::iterator findString(vector<string> word, string x)
{
...
}
And then later, where the error is:
vector<string>::iterator t = findString(word, x);
if (t != word.end()) //A: Error happens in this line.
And so findString is returning an iterator into a copy of word instead of word itself, and MS' vector implementation has an assertion failure when you try to compare it with an iterator from a different vector, because it figures you most likely made a mistake. Instead pass your vectors by reference, for example:
vector<string>::iterator findString(vector<string> & word, string x)
{
...
}
Note that word is now passed by reference, and so won't be copied.
That said, you should fix your error first as an exercise, of course, but after you've got your own code working, consider replacing findString with std::find (since it already exists). Also it seems you can simplify your code greatly by using a map<string,int> to maintain word counts. And a few other things.

Those two types are simply different and can't be converted one into the other. They are not "integers", they abstract a position in a container.
I think the actual problem you see is because your findString is returning an iterator relative to a copy of your words vector. When you compare that iterator to word.end(), the two iterators are relative to different containers, and the VC STL rightfully complains. Accept the vector by reference for a start.

Related

How to get a vector of strings from input?

I'm trying to get a vector of string from input to create a graph , but i don't know why in middle my code it crashes. please help me fix it. I use Visual Studio.
#include <iostream>
#include <vector>
#include <iterator>
void main(void)
{
{
using namespace std;
int8_t n{ 0 };
cout << "enter the size of graph : ";
cin >> n;
vector<string> graph(n);
string connectionsWith;
vector<string>::iterator i;
string::iterator e;
int p{ 0 };
for (i = graph.begin(); i != graph.end(); ++i)
{
cout << '\n' << "enter the vertices that are connected to " << p << " : ";
cin >> connectionsWith;
graph.push_back(connectionsWith);
p++;
}
p = 0;
for (i = graph.begin(); i != graph.end(); ++i)
{
cout << p << " is connected to " << *i;
p++;
}
}
}
In your constructor of graph, you allocate n string. Inside the loop you add on top of the constructed n strings, n more strings via push back. That potentially invalidates your iterators, as ChrisMM said, also not the most efficient way to implement such a scenario.
So as a solution, instead of
vector<string> graph(n);
do
vector<string> graph;
graph.reserve(n);
and iterate over the index, e.g. from 0 to n, and push back.
Especially in the first loop you are not dereferencing the iterator at all, which suggests that using index based loop would show your intent better.
life_steal pointed out the problem. I would like to add few information and other way to solve the problem.
int8_t n{ 0 };
vector<string> graph(n); // Here initialization happening with ASCII. If input is "1" then it would be "49". Consider changing int8_t to int if you unaware of that.
graph.push_back(connectionsWith); //Instead of this line Use: *i = connectionsWith; it directly assign the value.

Getting run-time error while USING SET(C++) to check if two given strings are anagrams

Link to the problem:
https://www.hackerearth.com/practice/basic-programming/input-output/basics-of-input-output/practice-problems/algorithm/two-strings-4/
I have started with set and map these days.
Two strings str1 and str2 have equal length.
I have to tell if they are anagrams of each other.
I used unordered_map to solve the problem by maintaining the count of characters which works in linear time and is great.
But I want to use unordered_multiset but i am getting a run-time error.
code:
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;// number of testcases
cin>>t;
while(t--){
string str1,str2;// two strings of equal length str1 and str2
cin>>str1>>str2;
unordered_multiset<char> s1,s2;// two sets
for(int i=0;i<str1.length();i++){
s1.insert(str1[i]);// initialization
s2.insert(str2[i]);
}
unordered_multiset<char>::iterator itr;
for(itr=s1.begin();itr!=s1.end();itr++){
if(s2.find(*itr)!=s2.end()) s2.erase(itr);/* if *itr is present in s2 then delete its address .....
i know i am making mistake somewhere here but i can't figure out*/
else {
cout<<"NO"<<"\n";// print NO if not found
break;
}
}
if(itr==s1.end()) cout<<"YES"<<"\n";// if itr reached the end print YES
}
}
The idea is to loop through the set s1 and find the corresponding element in the set s2. If not found print NO and break otherwise delete the corresponding element from s2 and since i am using iterator to delete elements so if there are multiple occurrences of a character then 1st occurrence should be deleted.
please let me know if you didn't get my question
Try to solve it in a simpler way. The problem states that there are only lowercase characters, you can use only a frequency array for each word, an then compare it.
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while(t--)
{
vector<int> f1(26, 0);
vector<int> f2(26, 0);
string s1, s2;
cin >> s1 >> s2;
for(const char& c : s1) f1[c - 'a']++;
for(const char& c : s2) f2[c - 'a']++;
cout << ( (f1 == f2)? "YES" : "NO") << endl;
}
}
It's because you are using the iterator from s1 to erase an element from s2:
if(s2.find(*itr)!=s2.end()) s2.erase(itr);
It have to be like this:
if(s2.find(*itr)!=s2.end()) s2.erase(*itr);
or:
auto elem = s2.find(*itr);
if (elem != s2.end())
s2.erase(elem);

Printing contents of a vector [duplicate]

This question already has answers here:
How do I print out the contents of a vector?
(31 answers)
Closed 5 years ago.
I am trying to get a feel for C++, and I want to either print the contents of a vector, or, to confirm my program is correct, I could add the contents of my vector and print the result.
Here is my code:
#include <iostream>
#include <vector>
using std::vector;
using std::cin;
using std::cout;
int main(){
int n;
vector<int> result;
cin >> n;
vector<int> numbers(n);
for(int i = 0; i < n; ++i){
cin >> numbers[i];
}
result = numbers;
cout << result;
return 0;
}
I found some solutions online for printing a vector, but I didn't understand what the code was doing, so I am hoping someone can help.
As you mentioned "I did not understand what the code is doing", let me briefly describe how to iterate through a container:
The long way:
vector<int> result = { 1,2,3 };
for (vector<int>::iterator it = result.begin(); it != result.end() ; it++) {
int i = *it;
cout << i << " ";
}
Each container provides an iterator, which you can think of a pointer moving forward along the elements of the container. begin() returns a pointer to the first element, end() returns a pointer to 1 past the last element. Dereferencing the iterator gives the actual value.
For above long way, with range-based for loops, C++ provides a shorthand notation with about the same meaning (i.e. it makes use of the iterator-concept but is less "clumsy" in notation):
for (auto i : result) {
cout << i << " ";
}
Try it out; hope it helps.
you can print the vector content by making a loop the print every index in the vector size
like
for(int i=0;i<numbers.size();i++){
cout<<numbers[i];
}
the loop will print every index until the end of the vector

Comparing items in an array while adding and deleting matches simultaneously

I have this message board, for sale, wanted, type of program below. Ive finally figured out how to read everything in, but need advice on how to compare items. As I read in the file, want to check the array to see if an item that is wanted(true) and mathces the name of an item already in the array and is for sale. If a match is found don't add that item, and delete the wanted item from the array, and shift.
#include <iostream>
#include <sstream>
#include <fstream>
#include <cstdlib>
#include <list>
using namespace std;
struct messageBoard {
string item;
bool forSale;
int price;
};
int main(){
messageBoard board;
const int arrayLength = 100;
std::list<messageBoard> arr;
int index = 0;
string filename;
ifstream words;
cout<<"Please enter the filename:";
cin>>filename;
words.open(filename);
if (words.fail()) {
cout << "file not found or something" << endl;
}else {
string word;;
while (getline(words, word)) {
int wordIndex = 0;
stringstream ss;
ss << word;
while (getline(ss, word, ',')){
if (wordIndex==0){
board.item = word;
}
else if (wordIndex==1&&word==" for sale"){
board.forSale = false;
}
else if (wordIndex==1&&word==" wanted"){
board.forSale = true;
}
else if (wordIndex==2){
board.price = atoi(word.c_str());
}
wordIndex++;
}
index ++;
arr.push_back(board);
}
}
words.close();
for(std::list<messageBoard>::iterator it = arr.begin(); it != arr.end(); it++) {
std::cout << "item: " << (it)->item << " bool: " << (it)->forSale <<"Price: "<<(it)->price << std::endl;
}
}
I won't write the code for you, but I'll tell you how I'd approach the problem.
First, I'd redefine arr as
std::list<MessageBoard> arr;
To add elements to the list, use list::push_back.
if an item that is wanted(true) and mathces the name of an item already in the array
Write a bool function that returns true if those conditions are met, else false.
Scan the list with std::find or std::find_if, using your function. If the search succeeds, the function returns an iterator pointing to the wanted item.
delete the wanted item
Use list::erase on the iterator. If you mess up, the result of deleting an invalid iterator is undefined, but likely your runtime library will let you know, loudly.
and shift
No need. The list length takes care of itself.
You might also consider std::set for efficient searches, or std::map<MessageBoard, int> to keep a count of identical elements.
By using the standard library containers, you elevate your logic from dealing with array elements by location, and move it closer to the problem of matching messages. You'll also write fewer loops.
If I may suggest, I'd call arr something like board or messages. Use the name to convey meaning not known to the compiler. Also, atoi is a bit out of place here. Since you're already in stringstream territory, you might as well extract the price that way.
stringstream sw(word);
sw >> arr[index].price;
HTH.

Inputting elements of unknown type into a vector

I'm working on a program that takes elements from a user and sorts them. For this program, I have to use a vector as the size of the element list is unknown prior to user input. Our instructions were:
Write a program in C++ to implement sorting of a list of elements.
Elements can be of any type but will all be of same type, like all
integers or all floats or all chars or all strings (strings shall be
sorted like in a dictionary). You can implement any sorting algorithm
of your choice.
Ask the user how many elements will be there
Ask the user to input elements
Ask the user to choose the sorting order: ascending or descending or both
Print both input and output lists
User will not provide any information regarding the type of elements
I'm not very familiar with vectors (teacher basically skimmed topic in class) and my book isn't giving me a whole lot of information on the subject. The problem I'm running into is that I don't know the type of the element list until the user begins input. So far, I have tried:
creating a void type vector (obviously not allowed now that I've researched it, oops)
overloading a function called insertInVector by sending the first element to the function and letting the function determine which vector type to create based on the type of the first element (which seemed like my best option when I thought of it, except I need access to the vector after the function terminates, so that ended up being a no go, too)
#include <typeinfo> in program, finding the type of the first element, and then
creating a vector using vector<typeid(firstElement).name()> and honestly I'm not
sure why that didn't work, but it didn't.
Like I said I have EXTREMELY limited experience with vectors as this is my first time using them. I'm also a fairly new programmer so a lot of the research I've done on this has gone over my head. Any help that could be given in this would be GREATLY appreciated!
C++ is a language statically typed. It means that all the types should be determined during compilation: you cannot introduce new types when running the program.
creating a void type vector (obviously not allowed now that I've researched it, oops)
void is actually quite a strange type, mostly a placeholder for when you would expect a type (like a function return type) and have none to provide. void* is used as a pointer to an unknown type (mostly in C) but this is quite a hack, because the information about the original is discarded (as far as the language is concerned) so this causes issues to actually do things with the value so obtained.
overloading a function called insertInVector by sending the first element to the function and letting the function determine which vector type to create based on the type of the first element
#include <typeinfo> in program, finding the type of the first element, and then creating a vector using vector<typeid(firstElement).name()> and honestly I'm not sure why that didn't work, but it didn't.
Unfortunately neither is possible: since you cannot declare a variable without a type, what would be the type of firstElement to begin with ?
The problem you are describing is difficult in general. Basically it means that you will have to accept a string of characters, and then code a set of rules to determine how to interpret those characters. This is done generically by using a grammar to encode those rules; but grammars might way complicated for what is probably a simple task.
Let me put together a small example:
class Input {
public:
enum Type {
Int,
Double,
String
};
static Input Parse(std::string const& s);
Input(): _type(Int), _int(0), _double(0.0) {} // need to define a default...
Type type() const { return _type; }
int asInt() const {
assert(_type == Int && "not an int");
return _int;
}
double asDouble() const {
assert(_type == Double && "not a double");
return _double;
}
std::string const& asString() const {
assert(_type == String && "not a string");
return _string;
}
private:
Type _type;
int _int;
double _double;
std::string _string;
};
Obviously, the real challenge is to correctly Parse the input.
The idea is to use a set of rules, for example:
an int is composed exclusively of digits, optionally prefixed by -
a double is composed exclusively of digits, with at most one . and optionally prefixed by -
a string can be anything, therefore is our catch-all
Then we can write the recognition part of the Parse method:
static bool isInt(std::string const& s) {
if (s.empty()) { return false; }
// The first character may be among digits and '-'
char const first = s.at(0);
if (not isdigit(first) and first != '-') { return false; }
// Subsequent characters may only be digits
for (char c: s.substr(1)) {
if (not isdigit(c)) { return false; }
}
// Looks like it is an int :)
return true;
} // isInt
// Note: any int could be interpreted as a double too
static bool maybeDouble(std::string const& s) {
if (s.empty()) { return false; }
// The first character may be among digits, '.' and '-'
char const first = s.at(0);
if (not isdigit(first) and first != '.' and first != '-') { return false; }
// There may only be one dot
bool hasSeenDot = s.at(0) == '.';
// Subsequent characters may only be digits and a dot now
for (char c: s.substr(1)) {
if (not isdigit(c) and c != '.') { return false; }
if (c == '.') {
if (hasSeenDot) { return false; } // no second dot allowed
hasSeenDot = true;
}
}
// Looks like it could be a double
return true;
} // maybeDouble
static Input::Type guessType(std::string const& s) {
if (isInt(s)) { return Input::Int; }
// Test double after we ensured it was not an int
if (maybeDouble(s)) { return Input::Double; }
return Input::String;
} // guessType
And with the guessing logic together, finally the parse comes:
Input Input::Parse(std::string const& s) {
Input result;
result._type = guessType(s);
switch(result._type) {
case Input::Int: {
std::istringstream stream(s);
s >> result._int;
return result;
}
case Input::Double: {
std::istringstream stream(s);
s >> result._double;
return result;
}
case Input::String:
result._string = s;
return result;
}
// Unreachable (normally)
abort();
} // Input::Parse
Phew!
So ? Almost there. Now we need to determine how to compare two inputs. It's easy if they all have the same type, if not you will need to determine an arbitrary logic. You can transform an input Int in an input Double easily enough, but for string it's a bit weirder.
// define < for comparing two instance of "Input",
// assuming they both have the same type
bool operator<(Input const& left, Input const& right) {
assert(left.type() == right.type() && "Different Types!");
switch(left.type()) {
case Input::Int: return left.asInt() < right.asInt();
case Input::Double: return left.asDouble() < right.asDouble();
case Input::String: return left.asString() < right.asString();
}
} // operator<
And finally, the program:
int main(int argc, char* argv[]) {
// parse command line
std::vector<Input> inputs;
// by convention argv[0] is the program name, it does not count!
for (int i = 1; i != argc; ++i) {
inputs.push_back(Input::Parse(argv[i]));
// Detect that the type is the same as the first input
if (inputs.size() >= 2) {
if (inputs.back().type() != inputs.front().type()) {
std::cerr << "Please only use one type among Int, Double and String\n";
return 1; // non-0 is an error
}
}
}
// sort
std::sort(inputs.begin(), inputs.end());
// echo back to the user
for (Input const& i: inputs) {
switch(i.type()) {
case Input::Int: std::cout << i.asInt() << "\n"; break;
case Input::Double: std::cout << i.asDouble() << "\n"; break;
case Input::String: std::cout << i.asString() << "\n"; break;
}
}
// End of the program
return 0;
}
Of course as I don't know the types you wish to deal with.. I've decided an arbitrary set ;) However this should give you a skeleton to base yourself on.
Looking at the actual requirements of the problem as stated in the comments, I suggest you store all the inputs in an std::vector<std::string> and sort the vector using std::sort. So, instead of worrying about different types, you can specify the sorting logic depending on what you interpret the strings in your vector to represent. So
Implement sorting functions for strings depending on what the strings represent (more later)
store inputs as strings in a vector.
Determine which type the strings represent
select the sorting function based on this type
Sort the vector using std::sort and the appropriate sort function.
Concerning the sorting function, std::sort accepts a binary functor or function that applies a "less-than" comparison to two elelemts, so your functors or functions should look something like
bool foo(const std::string& rhs, const std::string& lhs) {
// implement the logic
}
Edit: Looking at more recent comments, it seems that the main purpose if the exercise might have been to implement sorting algorithms for different types. In that case, I would suggest following the approach taken by the C++ standard library, that is, to implement sorting in terms or a less-than comparison between two types, thereby decoupling the sorting logic from the types to be sorted. So you would want a template sorting function, templated on iterator type and comparison function/functor.
If you know what are the types the user may input, you can use templates and inheritance:
class Generic {
public:
virtual void process_input() = 0; // Handles the next input from user
virtual void process_output() = 0; // Processes the data inserted
};
template <typename T>
class HandleInput : public Generic {
private:
std::vector<T> storage;
public:
HandleInput(T first)
{
storage.push_back(first);
}
void process_input()
{
// do whatever you want
}
void process_output()
{
// do whatever you want
}
};
int main(int argc, char **argv)
{
// Get first input
Input i = input();
Generic *g;
// Instantiate the "right" generic with a switch
switch (i.type) {
case T:
g = new HandleInput<T>(i.value);
}
// Use Generic from here onwards
}
That's just an idea (Input cannot be implemented like that, you need to change that part with the logic that gets something from the user and determines its type), but it has the benefit of masking the type into a generic class, so you can factor your code around the interface provided by Generic.
Another idea (easier, probably) is using a std::vector<void*> and an enum that tells you what the type of the data stored in the vector is. When you need to process that data somewhere in the future, you can switch on the enum to appropriately cast the vector elements to the correct type and dispatch them to the appropriate code.
EDIT: another idea is to define a templatized function that takes the input and sorts the array using standard comparators:
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lexical_cast.hpp>
template <typename T>
void print_v(std::vector<T> &v)
{
typename std::vector<T>::iterator it;
for (it = v.begin(); it != v.end(); it++)
std::cout << *it << " ";
std::cout << std::endl;
}
template <typename T>
void sort_and_print(T first, size_t n, bool asc)
{
std::vector<T> v;
v.push_back(first);
for (size_t i = 0; i < n; i++) {
std::string s;
std::cin >> s;
T e = boost::lexical_cast<T>(s);
v.push_back(e);
}
print_v(v);
if (asc)
std::sort(v.begin(), v.end(), std::greater<T>());
else
std::sort(v.begin(), v.end());
print_v(v);
}
int main(int argc, char **argv)
{
std::string s = "test";
sort_and_print(s, 2, true);
unsigned int j = 3;
sort_and_print(j, 2, true);
return 0;
}
The logic to determine the type of the first input is up to you (maybe you can open another question) ;)
There are two aspects to this question: parsing & sorting.
You can use regular expressions to check the user-input data-types.
You can use cin to parse the data.
First: realise that you cannot necessarily know the type of your
users input until you have received all of it
~eg: consider a list of user names :
728278243
390349346
495045594
elizabeth
Hence, best not to assume to know best about the incoming data (can lead to a frustrating user-experience) but instead, prefer to treat everything as potentially a string. Store all raw input as strings so you can output in same format as input.
you can use say, an enumerated type to switch inside a sort comparator
or consider using a mutliset/multimap. here you will be
building an ordered set. so there is no need to sort.
NB: the complexity for constructing an ordered set of N elements or, for a single sort on N unsorted list elements, is roughly equivalent ~> NlogN
For your task-in-hand, it hardly matters but in reality depending upon upon how the list is used, one or other approach will be far more appropriate in performance terms.
If you have already used the likes of std::vector then std::multimap shouldn't be too scary. Loosely, it is an associated array of key-value pairs. the multi here meaning it can store multiple elements with the same key (which here, you want).
In this example i am using the boost regex library in order to determine some funky input data-types.
(eg: sudo apt-get install libboost-regex1.46-dev)
This regex might seem arcane but there are many examples on the i/web for practically every conceivable pattern.
[NB: C++11 regex is pretty-much a drop-in replacement for boost regex. ie: boost regex should be forward-compatible with the emerging C++11 standard]
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;
}
Example was compiled & run on Ubuntu. Commandline stuff:
$
$ 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 example code:
There are many optimisations that can be made here. You clearly
don't need so many stl containers as i am using.
I do not strictly deal with the direction of the sort (but show a couple of ways it may be achieved).
It might also be nice to encapsulate the type-specific functionality
in C++ objects; have a base class & then derived classes for each type you wish
to support ~but this homework right? -so probably not worth going over-board then
;)