Is it possible to iterate over an iterator? - c++

I have a working program that capitalizes strings in a vector, using iterators:
vector<string> v7{ 10, "apples" };
for (auto vIterator= v7.begin(); vIterator!= v7.end(); ++vIterator){
auto word = *vIterator; //here
auto charIterator = word.begin();
*charIterator = toupper(*charIterator);
*vIterator = word; //also here, i guess i could just print `word` instead?
cout << *vIterator << endl;
}
My question is;
2nd line inside the loop # the comment, i had to save the pointer to the iterator to another string variable before i was able to iterate over it.
Iterating over the pointer like so
*vIterator.begin();
didn't seem to work.
Is this the correct practice, or am i missing something?
I'm new to the C languages, the concept behind pointer-like tools is quite hard to understand even if i can use them, and in this case it just feels like I'm doing it wrong.
Edit: It was a syntax error (*vIterator).begin();
It just didn't make sense why i'd have to save it to another variable before iterating over it, cheers.

Since you are using C++11 look how simpler your code can become using ranged loops like the example below:
std::vector<std::string> v(10, "apples");
for(auto &&word : v) {
word[0] = toupper(word[0]);
}
LIVE DEMO
Now as far as it concerns the (*vIterator.begin(); didn't seem to work.):
The dot operator (i.e., .) has a higher precedence than the dereference operator (i.e., *). Thus, *vIterator.begin() is interpreted as *(vIterator.begin()). The compiler rightfully complains because vIterator hasn't got a member begin().
Think of iterators as if they were pointers. The correct way to access the members of an object via a pointer/iterator pointing to it is either using the arrow operator (i.e., vIterator->begin()) or first dereference the pointer/iterator and then use the dot operator (i.e., (*vIterator).begin()).
So your code via the use of iterators would become:
std::vector<std::string> v(10, "apples");
for(auto it(v.begin()), ite(v.end()); it != ite; ++it) {
*(it->begin()) = toupper(*(it->begin()));
}
LIVE DEMO

The correct way to write *vIterator.begin(); is (*vIterator).begin(); or, more often, vIterator->begin();. Also note that you can also access the first character of a string directly (without having to iterate over it) as word[0].

A simple STL-ish way of doing it:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<string> v7{ 10, "apples" };
for_each(v7.begin(), v7.end(), [](string& word){word[0] = toupper(word[0]);});
}

Related

C++: is it possible to use "universal" pointer to vector?

Good day, SO community!
I am new to C++ and I've ran into a situation in my project, where I have 2 vectors of similar paired data types:
std::vector<std::pair<int, std::string> firstDataVector
std::vector<std::pair<int, std::string> secondDataVector
and in one part of the code I need to select and process the vector depending on the external string value. So my question is - is it possible to create a pointer to vector outside of the conditions
if (stringValue.find("firstStringCondition"))
{
//use firstDataVector
}
if (stringValue.find("secondStringCondition"))
{
//use secondDataVector
}
some kind of pDataVector pointer, to which could be assigned the existing vectors (because now project has only two of them, but the vectors count might be increased)
I've tried to createstd::vector<std::string> &pDataVector pointer, but it will not work because reference variable must be initialized. So summarizing the question - is it possible to have universal pointer to vector?
You are trying to create a reference to one of the vectors - and that's certainly possible, but it must be initialized to reference it. You can't defer it.
It's unclear what you want to happen if no match is found in stringValue so I've chosen to throw an exception.
now project has only two of them, but the vectors count might be increased
Create a vector with a mapping between strings that you would like to try to find in stringValue and then the vector you'd like to create a reference to.
When initializing pDataVector, you can call a functor, like a lambda, that returns the reference.
In the functor, loop over the vector holding the strings you'd like to try to find, and return the referenced vector on the first match you get.
It could look like this:
#include <functional>
#include <iostream>
#include <string>
#include <vector>
int main() {
using vpstype = std::vector<std::pair<int, std::string>>;
vpstype firstDataVector{{1, "Hello"}};
vpstype secondDataVector{{2, "World"}};
// A vector of the condition strings you want to check keeping the order
// in which you want to check them.
std::vector<std::pair<std::string, std::reference_wrapper<vpstype>>>
conditions{
{"firstStringCondition", firstDataVector},
{"secondStringCondition", secondDataVector},
// add more mappings here
};
// an example stringValue
std::string stringValue = "ssdfdfsdfsecondStringConditionsdfsfsdf";
// initialize the vpstype reference:
auto& pDataVector = [&]() -> vpstype& {
// loop over all the strings and referenced vpstypes:
for (auto& [cond, vps] : conditions) {
if (stringValue.find(cond) != std::string::npos) return vps;
}
throw std::runtime_error("stringValue doesn't match any condition string");
}();
// and use the result:
for (auto [i, s] : pDataVector) {
std::cout << i << ' ' << s << '\n'; // prints "2 world"
}
}
You can indeed inintialize references conditionally. Either use a function or lambda that returns the vector you want to reference, or hard code it like below.
std::vector<std::string> &pDataVector =
(stringValue.find("firstStringCondition") != std::string::npos) ?
firstDataVector : ((stringValue.find("secondStringCondition") != std::string::npos) ?
secondDataVector : thirdDataVector);

C++ transform parameter initialization question

I was trying to transform a string into lowercase and store it in another variable using std::transform and std::tolower. I first tried:
string str1("Hello");
string lowerStr1;
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);
cout << lowerStr1 << endl;
But, lowerStr1 contained nothing. After initializing lowerStr1 with str1, I got the desired result. I want to know the intuition behind this. Could someone explain why lowerStr1 should be initialized in this case?
lowerStr1 is empty, and std::transform won't insert elements into it.
std::transform applies the given function to a range and stores the result in another range, beginning at d_first.
You can use std::back_inserter, which constructs a std::back_insert_iterator, which would call push_back() on the container to insert elements.
transform(str1.begin(), str1.end(), back_inserter(lowerStr1), ::tolower);
Or make lowerStr1 containing 5 elements in advance.
string lowerStr1(5, '\0');
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);
or
string lowerStr1;
lowerStr1.resize(5);
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);
Could someone explain why lowerStr1 should be initialized in this case?
That's because you initialize lowerStr1 containing 5 elements in advance as above. What's the value of the initialized elements doens't matter in fact.
This is because your call to std::transform is logically equivalent to the following code:
auto b=str1.begin();
auto e=str1.end();
auto p=lowerStr1.begin();
while (b != e)
{
*p=tolower(*b);
++b;
++e;
}
But lowerStr1, is a completely empty string. lowerStr1.begin() gives you, loosely speaking, a pointer to an empty string. So writing to that pointer and, adding insult to injury, incrementing it and continuing to write to it, result in undefined behavior, memory corruption, and a non-trivial possibility of a crash.
You do not add content to an empty string by grabbing a pointer to it, and then scribbling into that pointer. There are several ways of doing that correctly, with push_back() or insert() methods. You can also use an iterator that does that, like a std::back_insert_iterator, which can use with std::transform.
Generic algorithms won't change the size of the containers.
You need to use an iterator adapter which implements operator= in a special way so that it actually insert elements.
Therefore you can use back_inserter(lowerStr1) to make sure that lowerStr1 gets extended as trasform() does assignments.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string str1("Hello");
string lowerStr1;
transform(str1.begin(), str1.end(), std::back_inserter(lowerStr1), ::tolower);
cout << lowerStr1 << endl;
}

Comparing unordered_map vs unordered_set

First of all, what is the main difference between them?
The only thing i've found is that unordered_set has no operator [].
How should i access an element in unordered_set, since there is no []?
Which container is using random access to memory(or both)?
And which one of them faster in any sense or using less memory?
They are nearly identical. unordered_set only contains keys, and no values. There is no mapping from a key to a value, so no need for an operator[]. unordered_map maps a key to a value.
You can use the various find methods within unordered_set to locate things.
you can use iterators to access elements.
unordered_set <string> u{
"Dog",
"Cat",
"Rat",
"Parrot",
"bee"
};
for(auto& s:u){
cout << s << ' ';
}
unordered_set<string>::const_iterator point = u.find("bee");
How should I access an element in unordered_set (C++17)?
In C++ 17 a new function extract is added to unordered_set.
Specially, this is the only way to take move only object out of the set.
https://en.cppreference.com/w/cpp/container/unordered_set/extract
For example if you want third element of your unordered set.
Advance the iterator
std::advance(it,2);
Then extarct the value
s.extract(it).value();
Here is the complete code. try on any C++17 compiler.
#include <iostream>
#include <string>
#include <unordered_set>
#include <iterator>
int main()
{
//CREATE AN OBJECT
std::unordered_set<std::string> s;
//INSERT DATA
s.insert("aee");
s.insert("bee");
s.insert("cee");
s.insert("dee");
//NEED TO INCLUDE "iterator" HEADER TO USE "std::advance"
auto it = s.begin();
std::advance(it,2);
//USING EXTRACT
std::string sval = s.extract(it).value();
std::cout<<sval;
}
Note: if queried for out of bound index, nothing happens. No result.
Try changing your code
//ONLY FOUR ELEMENTS
std::advance(it,8);
//USING EXTRACT
std::string sval = s.extract(it).value();

Pointer to a map

If I define a pointer-to-map like this:
map<int, string>* mappings;
mappings is a pointer. How should I use this pointer to operate the map?
Use the pointer just like you use any other pointer: dereference it to get to the object to which it points.
typedef std::map<int, string>::iterator it_t;
it_t it1 = mappings->begin(); // (1)
it_t it2 = (*mappings).begin(); // (2)
string str = (*mappings)[0]; // (3)
Remember that a->b is — mostly — equivalent to (*a).b, then have fun!
(Though this equivalence doesn't hold for access-by-index like (*a)[b], for which you may not use the -> syntax.)
Not much difference except that you have to use -> for accessing the map members. i.e.
mapping->begin() or mapping->end()
If you don't feel comfortable with that then you can assign a reference to that and use it as in the natural way:
map<int, string> &myMap = *mappings; // 'myMap' works as an alias
^^^^^^^^
Use myMap as you generally use it. i.e.
myMap[2] = "2";
myMap.begin() or myMap.end();
For instance:
#include <map>
#include <string>
#include <iostream>
int main() {
std::map<int, std::string> * mapping = new std::map<int, std::string>();
(*mapping)[1] = "test";
std::cout << (*mapping)[1] <<std::endl;
}
With the introduction of "at" function in c++ 11, you can use mappings->at(key) instead of (*mapping)[key].
Keep in mind that this api will throw out_of_range exception if the key is not already available in the map.
another nice way of using pointers, which I like is calling mappings->(and the function you want to call)
Well, STL is designed to reduce the complexity of pointer handling..so better approach is to use stl::iterator.. try to avoid pointers :-/

getting object in each element in vector

Is there a way for an iterator to return an object in each element of a C++ Standard Library vector?
I have this code:
struct mystruct {
int field1;
}
int DoSomethingWithMyStruct(mystruct& a);
std::vector<mystruct> myVector;
std::vector<mystruct>::iterator it;
mystruct s1,s2, temp;
s1.field1=1;
s2.field1=2;
for (it=myVector.begin();it!=myVector.end();it++)
{
//I want to call DoSomethingWithMyStruct, so I have to pass in mystruct object.
//can I use iterator to get the object of each element in myVector without having to create a temporary mystruct object and pass it in?
//I'm looking for an easier way than having to do this:
temp.field1 = it->field1;
DoSomethingWithMyStruct(temp);
}
As well as what the others said, you can do this instead:
#include <algorithm>
std::for_each(myVector.begin(), myVector.end(), DoSomethingWithMyStruct);
It's short and succinct. No need of manual loop.
Yes:
DoSomethingWithMyStruct(*it);
Just dereference the iterator, surely:
std::vector<mystruct>::iterator it, end;
for (it = myVector.begin(), end = myVector.end(); it != end; ++it) {
DoSomethingWithMyStruct(*it);
}
Or am I missing something here...?
Going further, there are other ways to iterate. You could use BOOST_FOREACH or C++0x ranged-for to simplify the loop. You could also use an algorithm like std::for_each to remove it entirely!
(Remember that it->field1 is like (*it).field1, so you're already doing this... even though you're going on to make your code more complicated than is necessary afterwards!)
Just simply dereference your iterator. *it, and you get a mystruct. They behave like pointers in this regard.
But in the case if you wonder how to iterate over all fields of all elements of a vector, where the elements are polymorphic; e.g. std::vector<Base*>, it's a bit more difficult. Since C++ doesn't have reflection that would make this possible (semi)automatically, you need to do it manually. Something similar to the Visitor Pattern comes to mind.
You have not populated myVector
Could make code more efficent like this
std::vector<mystruct>::const_iterator theEnd;
for (it=myVector.begin();it!=theEnd;++it)
Notice the position of the ++
I think that &(*it) should work.