I have defied a range and I need to find the number of elements in it. My current code is
size_t c = 0;
for(auto elem : range){
c++;
}
return c;
However, the compiler is whining about the unused variable elem and I can't get rid of it. I though of using something like
std::count_if(range.begin(), range.end(), [](type elem){return ture;});
But I feel it is an overkill and it does not seem right.
I am wondering if there is a nicer systematic way of achieving this without defining an extra variable?
If (for some reason) your range doesn't have a size() member function, you can use std::distance. This should always work since a range is required to have a begin and end iterator.
std::distance(cbegin(range), cend(range));
You can use std::distance like
std::distance(range.begin(), range.end());
Returns the number of hops from first to last.
And note the complexity:
Complexity
Linear.
However, if InputIt additionally meets the requirements of
LegacyRandomAccessIterator,
complexity is constant.
In C++ all the containers implement size method of a constant complexity so if by range you consider a container then there is no need for reinventing the wheel.
However, you can also use std::distance if you want to determine the number of elements from a certain range like:
std::vector<int> v{ 3, 1, 4 };
std::cout << std::distance(v.begin(), v.end() << std::endl; // 3
If you take a look at the possible implementation of std::distance, it is something like
while (first != last) {
++first;
++n;
}
where first and the last are start and end point of you range, and n is a simple counter.
Related
std::multimap<std::string, std::string> authors;
authors.insert ({{"Steven,King", "Cujo"}, {"Jesse,James", "The Highlight"}});
auto it = authors.begin();
auto retVal2 = authors.erase(it+1);
for (auto &i : authors){
std::cout << i.first << " " << i.second << std::endl;
}
Is it not allowed to add values to the iterator to move to the desired location in the multimap?
In vectors this can be done.
Please clarify if there is anyway about this?
thank you.
std::multimap::iterator is a bidirectional iterator. A bidirectional iterator does not have operator+ because it can only advance one at a time making operator+ a very slow function. Maybe you're comparing it to the iterator of something like std::vector or std::array. However, those are random access iterators where operator+ can work in constant time.
Since you only need to add it by 1, you can easily replace it+1 with std::next(it). If you want to make a new iterator n elements after it you can also do std::next(it, n). Like std::next, there's also std::prev for going backwards. If you want to modify it itself, you can use operator++/operator-- (which act like how you would expect them to) or use std::advance(it, n) to go n elements forward or backward (There's no opposite of std::advance like std::recede, to make your iterator go back n should be a negative number).
palindromes implementation using reverse iterators
the error in code is of "operator /", is not defined for iterators
bool isPalindrome( std::string & s)
{
bool check = ( s == std::string{ s.rbegin(), s.rend() } );
return check; // works fine
}
in above there are n comparisons. ( n=s.length )
s == string{ s.rbegin(), s.rbegin() + (s.rend()/2) }
/* error: operator/ not defined */
I'm expecting a one or two lines of code for palindrome check with floor(n/2) comparisons.
Is there an elegant code. Am I missing something about reverse iterators?
and input of std::string{"cac"} should return true and should require 1 comparison
How to get mid-point in O(1) time, using reverse iterators
Dividing an iterator by a number does not really make sense. What you can do is obtain an iterator that is advanced half way the length of the container like this:
string{s.rbegin(), std::next(s.rbegin(), s.size() / 2)}
std::next obtains the iterator after incrementing it the supplied number of times.
This is only going to be efficient O(1) for contiguous containers like std::vector, std::array and std::string.
You are confusing something that references an element with the index of that element. Just think about what s.rend()/2 is supposed to mean. What you actually want is some difference between two indices divided by 2.
Given two iterators you can get their distance via std::distance.
How to get the last element of an std::unordered_map?
myMap.rbegin() and --myMap.end() are not possible.
There is no "last element" in a container that is unordered.
You might want an ordered container, e.g. std::map and access the last element with mymap.rbegin()->first (Also see this post)
EDIT:
To check if your iterator is going to hit the end, simply increment it (and possibly save it in a temporary) and check it against mymap.end(), or, even cleaner : if (std::next(it) == last)
In your comments, it appears your goal is to determine if you are on the last element when iterating forward. This is a far easier problem to solve than finding the last element:
template<class Range, class Iterator>
bool is_last_element_of( Range const& r, Iterator&& it ) {
using std::end;
if (it == end(r)) return false;
if (std::next(std::forward<Iterator>(it)) == end(r)) return true;
return false;
}
the above should work on any iterable Range (including arrays, std containers, or custom containers).
We check if we are end (in which case, we aren't the last element, and advancing would be illegal).
If we aren't end, we see if std::next of us is end. If so, we are the last element.
Otherwise, we are not.
This will not work on iterators that do not support multiple passes.
You cant. by definition, the element is not stored based on some sort of order. the key is hashed first and that's why O(1) search is possible. if you wanna check whether a key exists in the unordered_map or not, u can use this code:
std::unordered_map dico;
if(dico.count(key)!=0){
//code here
}
std::unordered_map::iterator last_elem;
for (std::unordered_map::iterator iter = myMap.begin(); iter != myMap.end(); iter++)
last_elem = iter;
// use last_elem, which now points to the last element in the map
This will give you the last element in whatever order the map gives them to you.
Edit: You need to use std::unordered_map<YourKeyType, YourValueType> instead of just std::unordered_map. I just wrote it like this because you did not provide the type in your question.
Alternatively, as suggested by vsoftco (thanks), you could declare both last_elem and iter as decltype(myMap)::iterator.
(If you're compiling with the MSVC++ compiler, then you will need to add typedef decltype(myMap) map_type; and then instead of decltype(myMap)::iterator use map_type::iterator.)
.end() is an iterator to the "element past the last element". That's why you compare it like this when you loop through a map:
for (auto it = myMap.begin(); it != myMap.end(); ++it) // '!=' operator here makes it possible to only work with valid elements
{
}
So you want the "last" element (whatever that may be, because it's not really guaranteed to be the last in an unordered map, since it ultimately depends on how the key was hashed and in which "bucket" it ends up in). Then you need: --myMap.end()
More specifically, .end() is a function, that returns an iterator, same as .begin() returns an iterator. Since there is no .rbegin() in an std::unordered_map, you have to use -- (the decrement operator):
auto it = --myMap.end();
To access the key you use it->first, to access the value you use it->second.
The accepted answer seems wrong. Unordered_map does have the last element even though the key-value pair is not stored in sorted order. Since the iterator of unorered_map is forwar_iterator(LegacyForwardIterator), the cost to find the last element is O(n). Yakk - Adam gave the correct answer. Essentially, you have to iterator the container from begin to end. At each iteration, you have to check whether the next element is end(); if yes then you are at the last element.
You cannot call prev(it) or --it. There will be no syntax error, but you will have a runtime error (more likely segmentation fault) when using the prev(it) or --it. Maybe next version of compiler can tell you that you have an logic error.
It may not be the best solution, performance-wise, but in C++11 and later, I use a combination of std::next() and size() to jump all elements from the beginning of the map, as shown below:
std::unordered_map<int,std::string> mapX;
...
if (mapX.size() > 0) {
std::unordered_map<int,std::string>::iterator itLast =
std::next(mapX.begin(), mapX.size() - 1);
...
Could this be the worst named function in the STL? (rhetorical question)
std::remove_copy_if() doesn't actually appear to do any removing. As best I can tell, it behaves more like copy_if_not.
The negation is a bit confusing, but can be worked around with std::not1(), however I might be misunderstanding something as I cannot fathom what this function has to do with removing - am I missing something?
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
Editing to add an example so readers are less confused.
The following program appears to leave the input range (V1) untouched:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using std::cout;
using std::endl;
int main (void)
{
std::vector<int> V1, V2;
V1.push_back(-2);
V1.push_back(0);
V1.push_back(-1);
V1.push_back(0);
V1.push_back(1);
V1.push_back(2);
std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
std::remove_copy_if(
V1.begin(),
V1.end(),
std::back_inserter(V2),
std::bind2nd(std::less<int>(), 0));
std::copy(V2.begin(), V2.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
}
It outputs:
-2 0 -1 0 1 2
0 0 1 2
-2 0 -1 0 1 2
I was expecting so see something like:
-2 0 -1 0 1 2
0 0 1 2
0 0 1 2 ? ? ?
Where ? could be any value. But I was surprised to see that the input range was untouched, & that the return value is not able to be used with (in this case) std::vector::erase(). (The return value is an output iterator.)
Could this be the worst named function in the STL?
A bit of background information: in the standard library (or the original STL), there are three concepts, the containers, the iterators into those containers and algorithms that are applied to the iterators. Iterators serve as a cursor and accessor into the elements of a range but do not have a reference to the container (as mentioned before, there might not even be an underlying container).
This separation has the nice feature that you can apply algorithms to ranges of elements that do not belong to a container (consider iterator adaptors like std::istream_iterator or std::ostream_iterator) or that, belonging to a container do not consider all elements (std::sort( v.begin(), v.begin()+v.size()/2 ) to short the first half of the container).
The negative side is that, because the algorithm (and the iterator) don't really know of the container, they cannot really modify it, they can only modify the stored elements (which is what they can access). Mutating algorithms, like std::remove or std::remove_if work on this premise: they overwrite elements that don't match the condition effectively removing them from the container, but they do not modify the container, only the contained values, that is up to the caller in a second step of the erase-remove idiom:
v.erase( std::remove_if( v.begin(), v.end(), pred ),
v.end() );
Further more, for mutating algorithms (those that perform changes), like std::remove there is a non-mutating version named by adding copy to the name: std::remove_copy_if. None of the XXXcopyYYY algorithms are considered to change the input sequence (although they can if you use aliasing iterators).
While this is really no excuse for the naming of std::remove_copy_if, I hope that it helps understanding what an algorithm does given its name: remove_if will modify contents of the range and yield a range for which all elements that match the predicate have been removed (the returned range is that formed by the first argument to the algorithm to the returned iterator). std::remove_copy_if does the same, but rather than modifying the underlying sequence, it creates a copy of the sequence in which those elements matching the predicate have been removed. That is, all *copy* algorithms are equivalent to copy and then apply the original algorithm (note that the equivalence is logical, std::remove_copy_if only requires an OutputIterator, which means that it could not possibly copy and then walk the copied range applying std::remove_if.
The same line of reasoning can be applied to other mutating algorithms: reverse reverses the values (remember, iterators don't access the container) in the range, reverse_copy copies the elements in the range to separate range in the reverse order.
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
There is no such algorithm in the STL, but it could be easily implementable:
template <typename FIterator, typename OIterator, typename Pred>
FIterator splice_if( FIterator first, FIterator last, OIterator out, Pred p )
{
FIterator result = first;
for ( ; first != last; ++first ) {
if ( p( *first ) ) {
*result++ = *first;
} else {
*out++ = *first;
}
}
return result;
}
is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
The closest thing I can think of is std::stable_partition:
std::vector<int> v;
// ...
auto it = std::stable_partition(v.begin(), v.end(), pick_the_good_elements);
std::vector<int> w(std::make_move_iter(it), std::make_move_iter(v.end()));
v.erase(it, v.end());
Now v will contain the "good" elements, and w will contain the "bad" elements.
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
Not really. The idea is that the modifying algorithms are allowed to "move" (not in the C++ sense of the word) elements in a container around but cannot change the length of the container. So the remove algorithms could be called prepare_for_removal.
By the way, C++11 provides std::copy_if, which allows you to copy selected elements from one container to another without playing funny logic games with remove_copy_if.
You are right, that is what it does... std::remove_copy_if copies the vector, removing anything that matches the pred.
std::remove_if ... removes on condition (or rather, shuffles things around).
I agree that remove is not the best name for this family of functions.
But as Luc said, there's a reason for it working the way it does, and the GoTW item that he mentions explains how it works. remove_if works exactly the same way as remove - which is what you would expect.
You might also want to read this Wikibooks article.
So, I wrote a bunch of code that accesses elements in an stl vector by index[], but now I need to copy just a chunk of the vector. It looks like vector.insert(pos, first, last) is the function I want... except I only have first and last as ints. Is there any nice way I can get an iterator to these values?
Try this:
vector<Type>::iterator nth = v.begin() + index;
way mentioned by #dirkgently ( v.begin() + index ) nice and fast for vectors
but std::advance( v.begin(), index ) most generic way and for random access iterators works constant time too.
EDIT
differences in usage:
std::vector<>::iterator it = ( v.begin() + index );
or
std::vector<>::iterator it = v.begin();
std::advance( it, index );
added after #litb notes.
Also; auto it = std::next(v.begin(), index);
Update: Needs a C++11x compliant compiler
You can always use std::advance to move the iterator a certain amount of positions in constant time:
std::vector<int>::iterator it = myvector.begin();
std::advance(it, 2);
Actutally std::vector are meant to be used as C tab when needed. (C++ standard requests that for vector implementation , as far as I know - replacement for array in Wikipedia)
For instance it is perfectly legal to do this folowing, according to me:
int main()
{
void foo(const char *);
sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');
foo(&vec[0]);
}
Of course, either foo must not copy the address passed as a parameter and store it somewhere, or you should ensure in your program to never push any new item in vec, or requesting to change its capacity. Or risk segmentation fault...
Therefore in your exemple it leads to
vector.insert(pos, &vec[first_index], &vec[last_index]);