How to iterate through a List function? - c++

I'm running a test program where I make a list of strings and try to find which strings have a certain suffix or prefix.
#include <iostream>
#include <list>
#include <string>
using namespace std;
list<string> beginWith(const string& pre, list <string> test);
list<string> endWith(const string& suf,list <string> test);
int main(){
list <string> testList(5);
string suffix = "able";
string prefix = "M";
testList.push_back("Agreeable");
testList.push_back("Doable");
testList.push_back("Machine");
testList.push_back("Makeable");
testList.push_back("Available");
for(list <string>::const_iterator it = testList.begin(); it != testList.end(); it++){
cout << *it << endl;
}
for(list <string>::const_iterator it = beginWith(prefix, testList).begin(); it != beginWith(prefix, testList).end(); it++){
cout << *it << endl;
}
for(list <string>::const_iterator it = endWith(suffix, testList).begin(); it != endWith(suffix, testList).end(); it++){
cout << *it << endl;
}
return 0;
}
list<string> beginWith(const string& pre, list<string> test){
list <string> answer;
for(list <string>::const_iterator it = test.begin(); it != test.end(); it++){
if(pre == it->substr(0, pre.length())){
answer.push_back(*it);
}
}
return answer;
}
list<string> endWith(const string& suf, list <string> test){
list <string> answer;
for(list <string>::const_iterator it = test.begin(); it != test.end(); it++){
if(suf == it->substr(it->length() - suf.length() , it->back())){
answer.push_back(*it);
}
}
return answer;
}
I declared a list of strings printed them out with the first for-loop. I also have 2 functions which will iterate through that list and then return a list of strings that have a certain prefix or suffix. I'll print those out with the 2nd and 3rd for-loop. The 1st for-loop prints out correctly however, I get a segmentation fault: 11 when I print out the 2nd and 3rd for loops. I'm confused as to how I would get those for-loops to iterate through the list functions and print out the contents.

beginWith and endWith return a list by value. This makes the for-loops call begin() and end() on different copies of the list.

list<string> beginWith(const string& pre, list<string> test) {
list <string> answer;
for (auto word : test) // Use C++ auto to iterate collection
{
cout << "Testing " << word << " against " << pre << " ... ";
if (word.find(pre) == 0) // From http://thispointer.com/c-check-if-a-string-starts-with-an-another-given-string/
{
cout << "match!";
answer.push_back(word);
}
cout << '\n';
}
return answer;
}
list<string> endWith(const string& suf, list <string> test) {
list <string> answer;
for (auto word : test)
{
cout << "Testing " << word << " against " << suf << " ... ";
if (word.size() >= suf.size() &&
word.compare(word.size() - suf.size(), suf.size(), suf) == 0) // From http://thispointer.com/c-how-to-check-if-a-string-ends-with-an-another-given-string/
{
cout << "match!";
answer.push_back(word);
}
cout << '\n';
}
return answer;
}
int main(int argc, wchar_t *argv[])
{
list <string> testList {}; // Create empty list, not list with five elements
string suffix = "able";
string prefix = "M";
testList.push_back("Agreeable");
testList.push_back("Doable");
testList.push_back("Machine");
testList.push_back("Makeable");
testList.push_back("Available");
for (auto word : testList) {
cout << word << '\n';
}
auto prefixedWords = beginWith(prefix, testList);
cout << "Prefixed words: \n";
for (auto prefixed : prefixedWords) {
cout << " " << prefixed << '\n';
}
auto suffixedWords = endWith(suffix, testList);
cout << "Suffixed words: \n";
for (auto suffixed : suffixedWords) {
cout << " " << suffixed << '\n';
}
return 0;
}
Program output:
Agreeable
Doable
Machine
Makeable
Available
Testing Agreeable against M ...
Testing Doable against M ...
Testing Machine against M ... match!
Testing Makeable against M ... match!
Testing Available against M ...
Prefixed words:
Machine
Makeable
Testing Agreeable against able ... match!
Testing Doable against able ... match!
Testing Machine against able ...
Testing Makeable against able ... match!
Testing Available against able ... match!
Suffixed words:
Agreeable
Doable
Makeable
Available

Related

C++ Multimap Printing

I'm trying to make a name, and then give a list of courses this person has taken. Here is my code currently:
#include <iostream>
#include <string>
#include <map>
#include <list>
using namespace std;
int main()
{
multimap<string,string> students;
students.insert(make_pair("john","cs1"));
students.insert(make_pair("john","cs2"));
for (auto itr = students.begin(); itr != students.end(); ++itr)
{
cout << itr->first << '\t' << itr->second << '\n';
}
}
This prints out:
John CS1
John CS2
If I wanted to make it print out the first value and then print out all second values, how would I do this? Do I need to use a list as the second value or something? Or is this doable with just multimaps? For example:
John CS1 CS2
You can use equal_range to achieve what you wanted, see:
std::string current_key = "";
for (auto itr = students.begin(); itr != students.end(); ++itr)
{
if(current_key == itr->first) {
continue;
} else {
current_key = itr->first;
}
const auto result = students.equal_range(itr->first);
cout << itr->first << ": ";
for(auto it = result.first; it != result.second; ++it) {
cout << it->second << " ";
}
cout << endl;
}
See working example here: https://ideone.com/RqCFOk
You'll may eventually end up creating a class to model a student, in the meantime, you could just iterate over the multimap container and check if the current key is the same as the previous:
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <string>
using students_t = std::multimap<std::string, std::string>;
void print_students_list(students_t const& students)
{
// Start printing the name of the first student and the first course (the first key-value
// pair) if the container is not empty.
auto student{ students.cbegin() };
if ( student == students.cend() )
return;
std::cout << std::setw(12) << std::left << student->first
<< std::setw(8) << student->second;
// Then iterate over the rest of the container printing the name (after a newline)
// only if it's different from the previous one.
for ( auto prev{ student++ }; student != students.cend(); prev = student, ++student )
{
if ( student->first != prev->first )
std::cout << '\n' << std::setw(12) << student->first;
std::cout << std::setw(8) << student->second;
}
std::cout << '\n';
}
int main()
{
students_t students {
{"john", "cs1"},
{"john", "cs2"},
{"Karen", "cs2"},
{"Karen", "nc1"},
{"Karen", "nc2"},
{"Bob", "nc1"}
};
print_students_list(students);
}

find the longest word in a vector c++

So i have a c++ vector which contains about 106 thousand words which are stored on vector<string>words i need to find the longest word in this vector and i also need to get the location at which the word is, for example (1,2,3) in my vector. I need this location because i have two other vectors which has the meaning and the type for the words. vector<string>definition, vector<string>type
Please help
My current code
this code is not working at all
copy_if(words.begin(), words.end(), back_inserter(length), [](const string& x) { return x.length() > 40; });// looks for words longer than 7 letters
for (const string& s : length)
{
cout << "found!!" << endl;
auto i = find(words.begin(), words.end(), s);//looks for the word in the words vector
if (i != words.end())
{
auto pos = i - words.begin();
//displays the word, type and the definition of the word that the user has entered
cout << "Word : " << words[pos] << '\n';
cout << "Type : " << definitions[pos] << '\n';
cout << "Definition: " << types[pos] << '\n';
cout << '\n';
}
else
cout << "word not found" << endl;
}
You could use the standard algorithm std::max_element to search through the vector<string>.
Example:
#include <algorithm> // max_element
#include <iostream>
#include <iterator> // distance
#include <string>
#include <vector>
int main() {
std::vector<std::string> words{"a", "bb", "ccc"};
auto it = std::max_element(words.begin(), words.end(),
[](const auto& a, const auto& b) {
return a.size() < b.size();
});
std::cout << "The longest word is " << *it << " at (zero-based) pos "
<< std::distance(words.begin(), it) << '\n';
}
Output:
The longest word is ccc at (zero-based) pos 2
I would prefer thinking simply: just check length of elements according to each indice and update information according to that.
std::vector<std::string> length;
// initialize the vector length
size_t max_length = 0; // the length of longest word(s)
std::vector<size_t> max_indice; // the indice of longest word(s)
for (size_t i = 0; i < length.size(); i++) {
size_t this_len = length[i].length();
if (this_len > max_length) {
// new record
max_length = this_len;
max_indice.clear();
max_indice.push_back(i);
} else if (this_len == max_length) {
// tie
max_indice.push_back(i);
}
}
for (size_t pos : max_indice) {
cout << "Word : " << words[pos] << '\n';
cout << "Type : " << definitions[pos] << '\n';
cout << "Definition: " << types[pos] << '\n';
cout << '\n';
}

Counter for items in an inventory using iterators

I'm somewhat new to vectors and iterators and I'm trying to figure out how to display an amount of items using an iterator. One example would be you have 5 apples. I would want it to output "5x Apple" or something of that sort. I have no idea how one might accomplish this. Here's a simple code that has the user put in a string to add to the inventory.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string item;
vector<string> inventory;
vector<string>::iterator iter;
int main()
{
while(true){
cin >> item;
inventory.push_back(item);
cout << "INVENTORY:\n";
for(iter = inventory.begin(); iter != inventory.end(); iter++)
cout << *iter << endl;
}
}
EDIT: I'm trying to make an inventory system for a game. That's why I thought i may need an iterator. If there's a better way to make an inventory system than using an iterator, please let me know. Apologies, i should have clarified.
An iterator lets you iterate through a container, but it does not do any counting for you.
A container's size() tells you how many items are in the container, but if you have different types of items then you have to count them yourself.
For instance, say you have 4 "apple" and 1 "orange".
You have to look at each item entered and count it as needed, eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> inventory;
int numApples = 0;
int numOranges = 0;
int numOther = 0;
int main()
{
string item;
while (cin >> item)
{
inventory.push_back(item);
if (item == "apples")
++numApples;
else if (item == "orange")
++numOranges;
else
++numOther;
}
cout << "INVENTORY:\n";
for (vector<string>::iterator iter = inventory.begin(); iter != inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : inventory)
cout << s << endl;
*/
cout << "# apples: " << numApples << endl;
cout << "# oranges: " << numOranges << endl;
cout << "# other: " << numOther << endl;
return 0;
}
Or, you might consider using std::count_if(), eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> inventory;
bool isApple(const string &s) { return (s == "apple"); }
bool isOrange(const string &s) { return (s == "orange"); }
bool isOther(const string &s) { return !(isApple(s) || isOrange(s)); }
int main()
{
string item;
while (cin >> item)
inventory.push_back(item);
cout << "INVENTORY:\n";
for (vector<string>::iterator iter = inventory.begin(); iter != inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : inventory)
cout << s << endl;
*/
cout << "# apples: " << count_if(inventory.begin(), inventory.end(), isApple) << endl;
cout << "# oranges: " << count_if(inventory.begin(), inventory.end(), isOrange) << endl;
cout << "# other: " << count_if(inventory.begin(), inventory.end(), isOther) << endl;
/* or, if you are using C++11 or later:
cout << "# apples: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s == "apple"); }) << endl;
cout << "# oranges: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s == "orange"); }) << endl;
cout << "# other: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s != "apple") && (s != "orange"); }) << endl;
*/
return 0;
}
Update: based on another question you posted, try something more like this instead:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> other_inventory;
int numApples = 0;
int numOranges = 0;
int main()
{
string item;
while (cin >> item)
{
if (item == "apples")
++numApples;
else if (item == "orange")
++numOranges;
else
other_inventory.push_back(item);
}
cout << "INVENTORY:\n";
if (numApples > 0)
cout << "# apples: " << numApples << endl;
if (numOranges > 0)
cout << "# oranges: " << numOranges << endl;
for (vector<string>::iterator iter = other_inventory.begin(); iter != other_inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : other_inventory)
cout << s << endl;
*/
return 0;
}
A way to simplify this is to sort the items in the inventory. That will bring the identical ones together, which simplifies counting them. Start at the beginning, count the number of consecutive items that match the current one, display it, and continue with the first non-matching one.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string item;
std::vector<std::string> inventory;
while (true) {
std::cin >> item;
if (item == "quit") return 0;
inventory.push_back(item);
std::sort(inventory.begin(), inventory.end());
std::cout << "INVENTORY:\n";
auto current = inventory.begin();
while (current != inventory.end()) {
int count = 1;
auto probe = current + 1;
while (probe != inventory.end() && *probe == *current) {
++count;
++probe;
}
std::cout << count << "x " << *current << '\n';
current = probe;
}
std::cout.flush();
}
return 0;
}
In more detail, if your inventory is {"orange", "apple", "orange"}, then the sort will rearrange the order to {"apple", "orange", "orange"}. Note that the identical ones are together.
Now the iterator current starts at the beginning ("apple"). We set count to 1 because we know there's at least 1. We set the iterator probe to point to the next item ("orange"). Since the value at probe doesn't match the value at current, the inner loop does nothing. We print count and the current item ("apple"). We continue by setting current to probe, because, at this point, probe will point to the first item that didn't match the current one.
On the second iteration, current refers to the first "orange". We reset count to 1 and start probe at the next item ("orange"). Since the values at match, we increment count (now 2) and advance probe (now at the end of the inventory). We print count (2) and the current item ("orange"), and set current to probe (end of the list). The outer loop condition sees we're at the end of the inventory, so the loop terminates.
inventory.size()
returns the number of items in your vector.
I don't see how you would need an iterator for that task.

How can I transform a user-defined string into an integer

I basically ask a user to input a string, let's say they input "ABC" or"DEF"
Then, I want to set a certain integer = 1 if ABC is entered and 2 if DEF is entered.
If anything else is entered, then I want it to say invalid value.
So at the end, I'll have the integer i assigned to 1 or 2 if a valid value was entered.
#include<iostream>
#include<string>
#include<sstream>
using namespace std;
int main()
{
string input = "";
// How to get a string/sentence with spaces
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
cout << ".\n" << "You entered: " << input << endl << endl;
int m
if(input = ABC)
return 0;
}
Very easy:
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<std::string, int> const v { { "ABC", 1 }, { "DEF", 2 } };
for (std::string line; std::getline(std::cin, line); )
{
auto it = v.find(line);
if (it == v.end())
{
std::cout << "Input '" << line << "' is invalid.\n";
}
else
{
std::cout << "Your input value: " << it->second << "\n";
}
}
}
Your English spec:
” set a certain integer = 1 if ABC is entered and 2 if DEF is entered […] if anything else is entered, then I want it to say invalid value.
Expressed in C++:
if( s == "ABC" ) { x = 1; }
else if( s == "DEF" ) { x = 2; }
else { cout << "Invalid value." << endl; }
If neither of the specified possibilites is true, i.e. in the case of outputting "Invalid value.", then x keeps the value it had, which is how I interpret the word “set”.
At a higher level of abstraction, it seems like you want the user to specify one of two strings, namely “ABC” or “DEF”, which you want to have available as an integer id after the input operation.
Then there are two main possibilities:
you want the id to indicate also the case where the user specified some other string, e.g. a common value for this, or
you want the input operation to only return control when the user has inputted one of the two valid strings.
The last case effectively means that input operation must loop or logically fail. Logical failure can be expressed as an exception, or e.g. by calling std::terminate.
So as you see there is a range of possibilities here, i.e. above the simple “how do I translate this English to C++” the desired functionality is a bit under-specified.
#include <iostream>
#include <map>
#include <string>
#include <initializer_list>
using namespace std;
int main()
{
const std::map<std::string, int> lookupTable = { {"ABC", 1}, {"DEF", 2} };
string input = "";
int m;
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end()) {
m = it->second;
break;
}
}
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
Second solution if you want your m const. This assumes your compiler supports lambda functions:
#include <iostream>
#include <map>
#include <string>
#include <initializer_list>
using namespace std;
int main()
{
const std::map<std::string, int> lookupTable = { {"ABC", 1}, {"DEF", 2} };
string input = "";
const int m = [&]() {
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end())
return it->second;
}
}();
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}
If your compiler does not support the above map initialization then you can use instead:
#include <iostream>
#include <map>
#include <string>
using namespace std;
std::map<std::string, int> initializeMap() {
std::map<std::string, int> map;
map["ABC"] = 1;
map["DEF"] = 2;
// add whatever else here
return map;
}
int main()
{
const std::map<std::string, int> lookupTable = initializeMap();
string input = "";
int m;
while(true) {
cout << "Please enter a valid sentence (with spaces):\n>";
getline(cin, input);
std::map<std::string, int>::const_iterator it = lookupTable.find(input);
if (it != lookupTable.end()) {
m = it->second;
break;
}
}
cout << "You entered: " << input << endl << endl;
cout << "m = " << m << endl;
}

How can I display the content of a map on the console?

I have a map declared as follows:
map < string , list < string > > mapex ; list< string > li;
How can I display the items stored in the above map on the console?
Update (Back to the future): with C++11 range-based for loops –
std::map<Key, Value> m { ... /* initialize it */ ... };
for (const auto &p : m) {
std::cout << "m[" << p.first << "] = " << p.second << '\n';
}
Well it depends on how you want to display them, but you can always iterate them easily:
typedef map<string, list<string>>::const_iterator MapIterator;
for (MapIterator iter = mapex.begin(); iter != mapex.end(); iter++)
{
cout << "Key: " << iter->first << endl << "Values:" << endl;
typedef list<string>::const_iterator ListIterator;
for (ListIterator list_iter = iter->second.begin(); list_iter != iter->second.end(); list_iter++)
cout << " " << *list_iter << endl;
}
I'd try the following
void dump_list(const std::list<string>& l) {
for ( std::list<string>::const_iterator it = l.begin(); l != l.end(); l++ ) {
cout << *l << endl;
}
}
void dump_map(const std::map<string, std::list<string>>& map) {
for ( std::map<string,std::list<string>>::const_iterator it = map.begin(); it != map.end(); it++) {
cout << "Key: " << it->first << endl;
cout << "Values" << endl;
dump_list(it->second);
}
I'm a little off topic here...
I guess you want to dump the map content for debugging. I like to mention that the next gdb release (version 7.0) will have a built in python interpreter which will be used by the gcc libstdc++ to provide stl pretty printers. Here is an example for your case
#include <map>
#include <map>
#include <list>
#include <string>
using namespace std;
int main()
{
typedef map<string, list<string> > map_type;
map_type mymap;
list<string> mylist;
mylist.push_back("item 1");
mylist.push_back("item 2");
mymap["foo"] = mylist;
mymap["bar"] = mylist;
return 0; // stopped here
}
which results in
(gdb) print mymap
$1 = std::map with 2 elements = {
["bar"] = std::list = {
[0] = "item 1",
[1] = "item 2"
},
["foo"] = std::list = {
[0] = "item 1",
[1] = "item 2"
}
}
Yay!
Another form, using <algorithm>:
void printPair(const pair<string, list<string> > &p)
{
cout << "Key: " << p.first << endl;
copy(p.second.begin(), p.second.end(), ostream_iterator<string>(cout, "\n"));
}
for_each(mapex.begin(), mapex.end(), printPair);
Test program:
#include <iostream>
#include <map>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
void printPair(const pair<string, list<string> > &p)
{
cout << "Key: " << p.first << endl;
copy(p.second.begin(), p.second.end(), ostream_iterator<string>(cout, "\n"));
}
int main()
{
map<string, list<string> > mapex;
list<string> mylist1;
mylist1.push_back("item 1");
mylist1.push_back("item 2");
mapex["foo"] = mylist1;
list<string> mylist2;
mylist2.push_back("item 3");
mylist2.push_back("item 4");
mylist2.push_back("item 5");
mapex["bar"] = mylist2;
for_each(mapex.begin(), mapex.end(), printPair);
}
You can write a quite generic overloaded function, which is good for two purposes:
It works with any map.
It allows for using <<.
The function is
template<class key_t, class value_t>
ostream& operator<<(ostream& os, const map<key_t, value_t>& m) {
for (typename map<key_t, value_t>::const_iterator it = m.begin();
it != m.end(); it++) {
os << "Key: " << it->first << ", Value: " << it->second;
}
return os;
}
cout << will work with any map for which << is defined for typenames key_t and value_t. In your case, this is not defined for value_t (= list<string>), so you also have to define it.
In a similar spirit, you can use
template<class T>
ostream& operator<<(ostream& os, const list<T>& l) {
for (typename list<T>::const_iterator it = l.begin(); it != l.end(); it++) {
os << "\"" << *it << "\", ";
}
return os;
}
So, you may:
Add these two functions.
Add the prototypes where needed.
Use using namespace std; (or add std:: as needed).
Use, e.g.,
cout << mapex << endl;
cout << li << endl;
Remember that if there is any other viable candidate for the <<s just defined (which I take there is not, otherwise you would likely not ask this question), it may take precedence over the present ones.
If you can use C++11 features, then I think range-based for loops as proposed in The Paramagnetic Croissant's answer provide the most readable option. However, if C++17 is available to you, then you can combine those loops with structured bindings to further increase readability, because you no longer need to use the first and second members. For your specific use case, my solution would look as follows:
std::map<std::string, std::list<std::string>> mapex;
mapex["a"] = { "1", "2", "3", "4" };
mapex["b"] = { "5", "6", "7" };
for (const auto &[k, v] : mapex) {
std::cout << "m[" << k.c_str() << "] =";
for (const auto &s : v)
std::cout << " " << s.c_str();
std::cout << std::endl;
}
Output:
m[a] = 1 2 3 4
m[b] = 5 6 7
Code on Coliru