How to make a list C++ [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
So I have to make a program that stores input piece by piece, until -1 is input. An example of this input would be 1 1 1 0 3 5 3 -1. And -1 would not be recorded. Then it plays the list back to you, but bacwards, so output would be 3 5 3 0 1 1 1
To do this I need to make a list of objects, but I have no clue how to declare them, or how to add/remove items to them. how do I do this?

You need a place to store values that can grow as values are read.
The simpler is probably std::vector, but also std::list or std::deque as well as whatever bidirectional container will do the game.
Then you need a loop to get the values an save them into the container (the push_back method has that purpose), and another loop getting the values from the container from the end and printing them.
This can be done using iterators or using indexes, depending on the container and on your own specific needs.
This may be a possibility:
#include <vector>
#include <iostream>
template<class V, class S>
void read_numbers(V& v, S& s, N end)
{
N x=0;
while(x << s)
{
if(x==end) return;
v.push_back(x);
}
std::cerr << "error: bad reading" << std::endl;
}
template<class V, class S>
void write_numbers(const V& v, S& s)
{
for(auto i=s.rbegin(); i!=s.rend(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
}
int main()
{
std::vector<int> nums;
read_numbers(nums, std::cin, -1); }
write_numbers(nums, std::cout);
return 0;
}

For a list of unknown size, you can declare a vector class:
std::vector<int> myVector;
Then to add an element, use push_back:
// assign some integer to myInt
myVector.push_back (myInt);
http://www.cplusplus.com/reference/vector/vector/push_back/

If you need to use a list, then you could use std::list.
You can declare them like this:
std::list<int> myList;
You can read more about std::list here.

You can use it for inspiration.
#include <vector>
#include <iostream>
int main(int argc, char * argv[]) {
std::vector<int> numbers;
int number;
do {
std::cin >> number;
if (number != -1) {
numbers.push_back(number);
}
} while(number != -1);
for (std::vector<int>::reverse_iterator it = numbers.rbegin(); it != numbers.rend(); ++it) {
std::cout << *it << " ";
}
std::cin.get();
return 0;
}

As was suggested already, you could use std::vector. It resizes as you push more elements. If the requirement is strictly a linked list, then go for std::list.
As to the requirement of playing them in reverse order, just use reverse_iterator and go through the list printing them.
std::list<int> mylist;
// Insert the elements.
for (std::list<int>::reverse_iterator rIt = mylist.rbegin();
rIt != mylist.rend(); ++rIt) {
cout << *rIt;
}

There are basically two options:
You can use a pointer int *data and manually allocate memory to it with new[]. You'll need to continually reallocate the array as you find that the array is larger than you expected.
You can use one of the wonderful containers that c++ provides. I might suggest std::vector.
Here's an example of how you might implement this:
#include <iostream>
#include <vector>
int main() {
std::vector<int> data;
while (true) {
int number;
std::cin >> number;
if (!std::cin)
break;
if (number == -1)
break;
data.push_back(number);
}
for (int datum : data)
std::cout << datum << " ";
std::cout << "\n";
}

Related

Duplicate character in a string in array c++. It is throwing garbage please help me out [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 months ago.
Improve this question
I have created a program for finding the duplicate character in a string. It is throwing garbage please help me to find the error and also find out its solution. I have created two arrays array a and b array a is a character array and array b is a integer array. array a is storing the characyeer that occurred in the string and array b for storing their frequency. please help me to find out the error
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
string s;
int i,j,k,l,m,n=0;
cout<<"Enter a string:";
cin>>s;
while (s[i]!='\0')
{
j++;
i++;
}
char *a=(char *)malloc(j*sizeof(char));
int *b = (int *)malloc(j*sizeof(int));
for (i=0;i<j;i++)
{
b[i]=0;
}
for (i=0;i<j;i++)
{
l=0;
for (k=0;k<i;k++)
{
if (s[i]==a[k])
{
b[k]++;
}
else
{
l++;
}
}
if (l+1==i)
{
a[i]=s[i];
b[i]++;
n++;
}
}
i=0;
while (a[i]!='\0')
{
m++;
i++;
cout<<a[i];
}
for (i=0;i<m;i++)
{
if (b[i]>1)
{
cout<<a[i]<<"occurs "<<b[i]<<" times";
}
}
return 0;
}
Let's actually use C++:
#include <cctype>
#include <iostream>
#include <string>
#include <unordered_map>
int main() {
std::string sample{"rat cat bat"};
std::unordered_map<char, int> letterFrequencies;
for (auto c : sample) {
if (std::isalpha(c)) {
++letterFrequencies[c];
}
}
for (auto entry : letterFrequencies) {
if (entry.second > 1) {
std::cout << "'" << entry.first << "' occurs " << entry.second
<< " times.\n";
}
}
}
Output:
❯ ./a.out
't' occurs 3 times.
'a' occurs 3 times.
Analyzing your code is difficult, as it seems to do far more than what's necessary. What it's doing unnecessarily is difficult to determine as your variable names are awful. Even if I wanted to use your two array method, I wouldn't. This can be done manually with a single array.
I don't know what the point of the nested loops are at all. All you need to do is count, and then analyze. That doesn't require nesting. It's two distinct loops.
You sized a wrong. It should be the size of the alphabet, not the size of your string that might have repeated characters that you are trying to count. But like I said, this array is unnecessary.
Shortcomings of the example above are that upper case and lower case letters are treated as different letters. It's an easy enough fix using another function from <cctype>.
It also explicitly only lists letters that were repeated.
std::unordered_map is a key-value data structure (similar to a python dictionary), usually implemented as a hash-map, meaning that lookups are very fast. Our keys are the letters of the string, the value is the count. The other key property is that when using operator[], if the key doesn't exist, it will be created for us.
Here is a different program that doesn't use a map.
#include <array>
#include <cctype>
#include <iostream>
#include <string>
int main() {
std::string sample{"rat cat bat"};
std::array<int, 26> letterFrequencies{0};
for (auto c : sample) {
if (std::isalpha(c)) {
++letterFrequencies[std::toupper(c) - 'A'];
}
}
for (std::size_t entry = 0; entry < letterFrequencies.size(); ++entry) {
if (letterFrequencies[entry] > 1) {
std::cout << "'" << static_cast<char>(entry + 'A') << "' occurs "
<< letterFrequencies[entry] << " times.\n";
}
}
}
Output:
❯ ./a.out
'A' occurs 3 times.
'T' occurs 3 times.
This program treats upper case and lower letters as the same.

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.

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

Basic c++ function using vectors

I'm doing some exercises with vectors. I created a function that fill a vector with defined size but when I tried to make it n size, the vector apparently is filled with trash memory, it shows: 0x23fe20, and my code crash when I try to use the vector.
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
using namespace std;
int cargavn(int vec[]) // fill vector
{
int i, t;
cout << "vector size: ";
cin >> t;
for(i = 0 ; i <= t-1; i++)
{
cout << "v["<< i <<"]=";
cin >> vec[i];
}
return (1);
}
int main()
{
int vec[10]; // the vector, size here wont matter
cargavn(vec); // call fill vector n positions
cout << vec; // to test if the vector is well filled
system("PAUSE");
}
you are exprecting cout << vec to somehow pretty print the vector. It wont, it just prints its address
You need to loop over the contents and print each element
for(int i =0 ; i < 10 ; i++)
{
cout << vec[i];
}
Here's how it would look using modern C++:
#include <iostream>
#include <vector>
using namespace std;
void cargavn(vector<int> &vec)
{
int t;
cout << "vector size: ";
cin >> t;
for(int i = 0; t > 0; ++i, --t)
{
cout << "v["<< i <<"]=";
int v;
cin >> v;
vec.push_back(v);
}
}
ostream &operator<<(ostream &s, vector<int> const &vec)
{
s << '{';
bool first = true;
for (int v : vec)
{
if (!first)
{
s << ", ";
}
s << v;
first = false;
}
return s << '}';
}
int main()
{
vector<int> vec;
cargavn(vec);
cout << vec;
system("PAUSE");
return 0;
}
Things to understand about this version compared to yours:
Unnecessary includes are ommitted.
Prefer C++ containers like vector over C style arrays.
Use dynamically sized containers when they need to hold an arbitrary number of values provided by the user instead of fixed-size containers that break when the user enters too much data. See the rule of 0, 1, infinity.
When all control paths of a function return the same value, then the returned value is pointless and can be omitted. Particularly if none of the callers even bothers to check the return value. I suspect you had the intention of using the return value to indicate some kind of unexpected error. This is a C-style approach to error handling. C++ uses exceptions to deal with unexpected errors.
Overload operator<< to extend the stream insertion operator to decide how containers and your own custom types should be formatted. The standard library doesn't provide any such insertion operator for vector because there isn't any universally agreed upon way to decide how a vector of values should be formatted. So you decide this for yourself.
It is good form for main to return a value, even though this is not technically required.

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
;)