I need to iterate through the keys of a map, but looking ahead to future keys. For example:
map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << "\n";
//is the next element equal to 3?
auto next = it++;
std::cout << "equals 3" << next==3 << std::endl
}
but sometimes I don't want to see the next element (n+1), maybe I want to see the n+10 element, etc. How do I do this? If my list has 100 elements, and I arrive at element 99, then 99+10 is gonna break evrything. Is there a way to test if my iterator can achieve n+10?
The best solution I thougth of is to keep track of an index i and see if I can call it + 10 (that is, if i+10<mapSize). Bus is there a more elegant way? Maybe testing if the n+10 iterator exists or something?
Map does not sound like the appropiate data type for your use case. Try switching to a container that supports random access
I think that your are looking for something like std::advance (Please see here), but with an additional check, if the advance operation was past the end or not.
We can use a small lambda to do this kind of check. Since it uses only an increment operation, it should work for all type of containers.
Please see the following example to illustrate the function:
#include <iostream>
#include <map>
#include <iterator>
using Type = std::map<int, int>;
using TypeIter = Type::iterator;
int main() {
// Lambda to advance a container iterator and check, if that was possible
auto advanceAndCheck = [](const Type& t, const TypeIter& ti, size_t advance) -> std::pair<bool, TypeIter>
{ TypeIter i{ ti }; while ((i != t.end()) && (advance--)) ++i; return { i != t.end(), i }; };
// Test data
Type m{ {1,1}, {2,2}, {3,3}, {4,4}, {5,5} , {6,6} };
// Iterate over container
for (TypeIter it = m.begin(); it != m.end(); ++it) {
// Show some values
std::cout << it->first << "\n";
// Test
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 1);
if (OK && itn->first == 3) std::cout << "The next Element is 3\n";
}
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 5);
if (OK && itn->first == 6) std::cout << "The 5th next Element is 6\n";
}
}
}
Related
I am hoping you can help me out here. I have searched for other answers, but I havent found something that matches my specific situation (but if you do find one, please let me know the URL!). I have seen a lot of suggestions about using std::map instead of list and I dont mind switching the container if need be.
Currently, I have two Lists of pairs i.e.
std:list <std::pair<string,string>> outputList1;
std:list <std::pair<string,string>> outputList2;
I have populated each list with User Settings that I have retrieved from an SQL database (I omit the SQL retrieval code here).
Example list:
outputList1 (first, second)
CanSeeAll, True
CanSubmit, False
CanControl, False
OutputList2:
CanSeeAll, False
CanSubmit, True
CanControl, False
I want to iterate through both lists and find the mismatches. For example, find the first string of the first pair of the first list to find the matching first string in the second list, then compare the second string to determine whether they match, then print out the non matching pairs to a new string (eventually to file), and so on.
In this example, the final string would have CanSeeAll and CanSubmit as the final output since those are the two that mismatch.
Here is what I've tried so far, but I get a blank string:
std::list <std::pair<std::string,std::string>>::iterator it1 = outputList1.begin();
std::list <std::pair<std::string,std::string>>::iterator it2 = outputList2.begin();
string token;
while (it1 != outputList1.end()){
if((*it1).first == ((*it2).first))
{
if((*it1).second != ((*it2).second))
{
token.append((*it1).first);
token.append(",");
token.append((*it1).second);
token.append("\r\n");
}
it1++;
it2 = outputList2.begin();
}
it2++;
if (it2 == outputList2.end())
it1++;
}
I know this logic is flawed as it will skip the first pair on the second list after the first iteration, but this is the best I can come up with at the moment, and I am banging my head on the keyboard a the moment.
Thanks everyone!
As I understand the problem,
you want to compare every element of one list, to every other element of another list.
You could use a pair of nested range based for loops.
#include <list>
#include <string>
int main(){
std::list<std::pair<std::string,std::string>> l1;
std::list<std::pair<std::string,std::string>> l2;
for (auto x: l1){
for (auto y: l2){
//compare x to y
}
}
}
The answer uses an auxiliary map but, have in mind you will get better result if you use two maps (or hash tables) instead of two list.
// create a map for elements in l2
std::map<std::string, std::string> l2map;
// move elements from l2 to the map so we get O(N*log(N)) instead of O(n²)
for (std::list<std::pair<std::string,std::string> >::iterator it = l2.begin();
it != l2.end();
++it)
{
l2map.insert(*it);
}
// walk l1 and look in l2map
for (std::list<std::pair<std::string,std::string> >::iterator l1it = l1.begin();
l1it != l1.end();
++l1it)
{
// look for the element with the same key in l2
// l1it->first is the key form l1
std::map<std::string, std::string>::iterator l2it = l2map.find(l1it->first);
if (l2it != l2map.end()) {
// found, then compare
if (l1it->second != l2it->second) { // l1it->second is the value from l1
// mismatch
}
} else {
// not in l2
}
}
You could use std::mismatch with the pre-condition: all settings occur in the same order in both lists (you could do a sort if this is not the case)
auto iterPair = std::mismatch(l1.begin(), l1.end(), l2.begin());
while (iterPair.first != l1.end()) {
// TODO: Handle the mismatching iterators
iterPair = std::mismatch(iterPair.first + 1, l1.end(), iterPair.second + 1);
}
If the keys in your lists come in the same order, as in your example, you can traverse the lists linearly:
std::ostringstream s;
std:list<std::pair<string, string>>::const_iterator i2(outputList2.cbegin());
for(auto const &pair: outputList1) {
if(pair.second != i2->second) {
s << pair.first << ": " << pair.second << " != " << i2->second << endl;
}
++i2;
}
Alternatively, use STL algorithms:
#include <algorithm>
typedef std::list<std::pair<std::string, std::string>> List;
std::ostringstream s;
for(
auto itrs(
std::mismatch(
outputList1.cbegin(), outputList1.cend(), outputList2.cbegin()
, [](auto const &l, auto const &r){ return l.second == r.second; }))
; itrs.first != outputList1.cend()
; itrs = std::mismatch(itrs.first, outputList1.cend(), itrs.second
, [](auto const &l, auto const &r){ return l.second == r.second; }))
{
s << itrs.first->first << ": "
<< itrs.first->second << " != " << itrs.second->second
<< std::endl;
}
I have to process element from a deque (first to last), but at each iteraton I need to use one element and the next too. So I'm trying to write a for loop that starts with mydeque.begin() and finishes at mydeque[mydeque.size()-1]. Also; I would like to know if my iterator deque::iterator it has a next method (it->next()), to make operations like *it - *it->next(). Thank you very much.
Here's how:
#include <deque>
#include <iostream>
int main() {
std::deque<int> test = {1,2,3,4,5,6,7,8};
for(auto i = test.begin(); i != test.end(); i++) {
auto next = std::next(i);
std::cout << *i << *next << std::endl;
if(next==test.end())
{
//Do something. This is the last element.
break;
}
}
}
EDIT: Watch out for deques with only one element. Do this by performing a check such as if(test.begin()==test.end()).
EDIT: My initial solution was indeed a bit error prone and unprecise.
This can easily be done using iterators, see this little example:
#include <deque>
#include <iostream>
int main() {
std::deque<int> test = {1,2,3,4,5,6,7};
for(auto i = test.begin(); i != test.end(); ++i) {
auto next = std::next(i);
if(next != test.end()) {
std::cout << *i << " " << *next << std::endl;
}
}
}
You can simply increment the iterator by 2 and use std::next to also pick the following item (since the offset of std::next defaults to 1).
I have the following multiset in C++:
template<class T>
class CompareWords {
public:
bool operator()(T s1, T s2)
{
if (s1.length() == s2.length())
{
return ( s1 < s2 );
}
else return ( s1.length() < s2.length() );
}
};
typedef multiset<string, CompareWords<string>> mySet;
typedef std::multiset<string,CompareWords<string>>::iterator mySetItr;
mySet mWords;
I want to print each unique element of type std::string in the set once and next to the element I want to print how many time it appears in the list (frequency), as you can see the functor "CompareWord" keeps the set sorted.
A solution is proposed here, but its not what I need, because I am looking for a solution without using (while,for,do while).
I know that I can use this:
//gives a pointer to the first and last range or repeated element "word"
auto p = mWords.equal_range(word);
// compute the distance between the iterators that bound the range AKA frequency
int count = static_cast<int>(std::distance(p.first, p.second));
but I can't quite come up with a solution without loops?
Unlike the other solutions, this iterates over the list exactly once. This is important, as iterating over a structure like std::multimap is reasonably high overhead (the nodes are distinct allocations).
There are no explicit loops, but the tail-end recursion will be optimized down to a loop, and I call an algorithm that will run a loop.
template<class Iterator, class Clumps, class Compare>
void produce_clumps( Iterator begin, Iterator end, Clumps&& clumps, Compare&& compare) {
if (begin==end) return; // do nothing for nothing
typedef decltype(*begin) value_type_ref;
// We know runs are at least 1 long, so don't bother comparing the first time.
// Generally, advancing will have a cost similar to comparing. If comparing is much
// more expensive than advancing, then this is sub optimal:
std::size_t count = 1;
Iterator run_end = std::find_if(
std::next(begin), end,
[&]( value_type_ref v ){
if (!compare(*begin, v)) {
++count;
return false;
}
return true;
}
);
// call our clumps callback:
clumps( begin, run_end, count );
// tail end recurse:
return produce_clumps( std::move(run_end), std::move(end), std::forward<Clumps>(clumps), std::forward<Compare>(compare) );
}
The above is a relatively generic algorithm. Here is its use:
int main() {
typedef std::multiset<std::string> mySet;
typedef std::multiset<std::string>::iterator mySetItr;
mySet mWords { "A", "A", "B" };
produce_clumps( mWords.begin(), mWords.end(),
[]( mySetItr run_start, mySetItr /* run_end -- unused */, std::size_t count )
{
std::cout << "Word [" << *run_start << "] occurs " << count << " times\n";
},
CompareWords<std::string>{}
);
}
live example
The iterators must refer to a sorted sequence (with regards to the Comparator), then the clumps will be passed to the 3rd argument together with their length.
Every element in the multiset will be visited exactly once with the above algorithm (as a right-hand side argument to your comparison function). Every start of a clump will be visited (length of clump) additional times as a left-hand side argument (including clumps of length 1). There will be exactly N iterator increments performed, and no more than N+C+1 iterator comparisons (N=number of elements, C=number of clumps).
#include <iostream>
#include <algorithm>
#include <set>
#include <iterator>
#include <string>
int main()
{
typedef std::multiset<std::string> mySet;
typedef std::multiset<std::string>::iterator mySetItr;
mySet mWords;
mWords.insert("A");
mWords.insert("A");
mWords.insert("B");
mySetItr it = std::begin(mWords), itend = std::end(mWords);
std::for_each<mySetItr&>(it, itend, [&mWords, &it] (const std::string& word)
{
auto p = mWords.equal_range(word);
int count = static_cast<int>(std::distance(p.first, p.second));
std::cout << word << " " << count << std::endl;
std::advance(it, count - 1);
});
}
Outputs:
A 2
B 1
Live demo link.
Following does the job without explicit loop using recursion:
void print_rec(const mySet& set, mySetItr it)
{
if (it == set.end()) {
return;
}
const auto& word = *it;
auto next = std::find_if(it, set.end(),
[&word](const std::string& s) {
return s != word;
});
std::cout << word << " appears " << std::distance(it, next) << std::endl;
print_rec(set, next);
}
void print(const mySet& set)
{
print_rec(set, set.begin());
}
Demo
This is probably really simple, but I can't find a simple example for it.
I understand that with a hash_multimap you can have several values mapped to a single key. But how exactly would I access those values. All the examples I stumbled across always just access the first value mapped to the the key. Heres an example of what I mean
key : value
1 : obj1a;
2 : obj2a, obj2b, obj2c
how would I access obj2b and obj2c, not just obj2a
The usual multimap iteration loop is like this:
#include <unordered_multimap>
typedef std::unordered_multimap<K, V> mmap_t;
mmap_t m;
for (mmap_t::const_iterator it1 = m.begin(), it2 = it1, end = m.end(); it1 != end; it1 = it2)
{
// outer loop over unique keys
for ( ; it1->first == it2->first; ++it2)
{
// inner loop, all keys equal to it1->first
}
}
To iterate over just one key value, use equal_range instead.
std::pair<mmap_t::const_iterator, mmap_t::const_iterator> p = m.equal_range(key);
for (mmap_t::const_iterator it = p.first; it != p.second; ++it)
{
// use "it->second"
}
For example, equal_range returns an two iterators, to the begin and end of the matching range :
void lookup(const map_type& Map, int key)
{
cout << key << ": ";
pair<map_type::const_iterator, map_type::const_iterator> p =
Map.equal_range(key);
for (map_type::const_iterator i = p.first; i != p.second; ++i)
cout << (*i).second << " ";
cout << endl;
}
where we're using a map_type like
class ObjectT; // This is the type of object you want to store
typedef hash_multimap<int, ObjectT> map_type;
Just grab an iterator to the first one and increment it. If the keys are still equal, you've got another entry with the same key value. You can also use equal_range.
Given a sorted vector with a number of values, as in the following example:
std::vector<double> f;
f.pushback(10);
f.pushback(100);
f.pushback(1000);
f.pushback(10000);
I'm looking for the most elegant way to retrieve for any double d the two values that are immediately adjacent to it. For example, given the value "45", I'd like this to return "10" and "100".
I was looking at lower_bound and upper_bound, but they don't do what I want. Can you help?
EDIT: I've decided to post my own anser, as it is somewhat a composite of all the helpful answers that I got in this thread. I've voted up those answers which I thought were most helpful.
Thanks everyone,
Dave
You can grab both values (if they exist) in one call with equal_range(). It returns a std::pair of iterators, with first being the first location and second being the last location in which you could insert the value passed without violating ordering. To strictly meet your criteria, you'd have to decrement the iterator in first, after verifying that it wasn't equal to the vector's begin().
You can use STL's lower_bound to get want you want in a few lines of code. lower_bound uses binary search under the hood, so your runtime is O(log n).
double val = 45;
double lower, upper;
std::vector<double>::iterator it;
it = lower_bound(f.begin(), f.end(), val);
if (it == f.begin()) upper = *it; // no smaller value than val in vector
else if (it == f.end()) lower = *(it-1); // no bigger value than val in vector
else {
lower = *(it-1);
upper = *it;
}
You could simply use a binary search, which will run in O(log(n)).
Here is a Lua snippet (I don't have time to do it in C++, sorry) which does what you want, except for limit conditions (that you did not define anyway) :
function search(value, list, first, last)
if not first then first = 1; last = #list end
if last - first < 2 then
return list[first], list[last]
end
local median = math.ceil(first + (last - first)/2)
if list[median] > value then
return search(value, list, first, median)
else
return search(value, list, median, last)
end
end
local list = {1,10,100,1000}
print(search(arg[1] + 0, list))
It takes the value to search from the command line :
$ lua search.lua 10 # didn't know what to do in this case
10 100
$ lua search.lua 101
100 1000
$ lua search.lua 99
10 100
I'm going to post my own anser, and vote anyone up that helped me to reach it, since this is what I'll use in the end, and you've all helped me reach this conclusion. Comments are welcome.
std::pair<value_type, value_type> GetDivisions(const value_type& from) const
{
if (m_divisions.empty())
throw 0; // Can't help you if we're empty.
std::vector<value_type>::const_iterator it =
std::lower_bound(m_divisions.begin(), m_divisions.end(), from);
if (it == m_divisions.end())
return std::make_pair(m_divisions.back(), m_divisions.back());
else if (it == m_divisions.begin())
return std::make_pair(m_divisions.front(), m_divisions.front());
else
return std::make_pair(*(it - 1), *(it));
}
What if (in your case) d is less than the first element or more than the last? And how to deal with negative values? By the way: guaranteeing that your "d" lives between the first and the last value of your vector you can do like that:
// Your initializations
std::vector<double>::const_iterator sit = f.begin();
double upper, lower;
Here is the rest:
while ( *sit < d ) // if the element is still less than your d
++sit; // increase your iterator
upper = *sit; // here you get the upper value
lower = *(--sit); // and here your lower
Elegant enough? :/
You could do a search in your vector for your value (which would tell you where your value would be if it were in the vector) and then return the value before and after that location. So searching for 45 would tell you it should be at index=1 and then you would return 0 and 1 (depending on your implementation of the search, you'll either get the index of the smaller value or the index of the larger value, but this is easy to check with a couple boundary conditions). This should be able to run in O(log n) where n is the number of elements in your vector.
I would write something like this, didn't test if this compiles, but you get the idea:
template <typename Iterator>
std::pair<Iterator, Iterator> find_best_pair(Iterator first, Iterator last, const typename Iterator::value_type & val)
{
std::pair<Iterator, Iterator> result(last, last);
typename Iterator::difference_type size = std::distance(first, last);
if (size == 2)
{
// if the container is of size 2, the answer is the two elements
result.first = first;
result.first = first;
++result.first;
}
else
{
// must be of at lease size 3
if (size > 2)
{
Iterator second = first;
++second;
Iterator prev_last = last;
--prev_last;
Iterator it(std::lower_bound(second, last, val));
if (it != last)
{
result.first = it;
result.second = it;
if (it != prev_last)
{
// if this is not the previous last
// then the answer is (it, it + 1)
++result.second;
}
else
{
// if this the previous last
// then the answer is (it - 1, it)
--result.first;
}
}
}
}
return result;
}
I wrote up this little function, which seems to fit the more general case you wanted. I haven't tested it totally, but I did write a little test code (included).
#include <algorithm>
#include <iostream>
#include <vector>
template <class RandomAccessIt, class Container, class T>
std::pair<RandomAccessIt, RandomAccessIt> bracket_range(RandomAccessIt begin, RandomAccessIt end, Container& c, T val)
{
typename Container::iterator first;
typename Container::iterator second;
first = std::find(begin, end, val);
//Find the first value after this by iteration
second = first;
if (first == begin){ // Found the first element, so set this to end to indicate no lower values
first = end;
}
else if (first != end && first != begin) --first; //Set this to the first value before the found one, if the value was found
while (second != end && *second == val) ++second;
return std::make_pair(first,second);
}
int main(int argc, _TCHAR* argv[])
{
std::vector<int> values;
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> vals;
for (int i = 1; i < 9; ++i) values.push_back(i);
for (int i = 0; i < 10; ++i){
vals = bracket_range(values.begin(), values.end(),values, i);
if (vals.first == values.end() && vals.second == values.end()){ // Not found at all
std::cout << i << " is not in the container." << std::endl;
}
else if (vals.first == values.end()){ // No value lower
std::cout << i << ": " << "None Lower," << *(vals.second) << std::endl;
}
else if (vals.second == values.end()) { // No value higher
std::cout << i << ": " << *(vals.first) << ", None Higher" << std::endl;
}
else{
std::cout << i << ": " << *(vals.first) << "," << *(vals.second) << std::endl;
}
}
return 0;
}
Based on the code that tunnuz posted, here you have some improvements regarding bound checking:
template<typename T>
void find_enclosing_values(const std::vector<T> &vec, const T &value, T &lower, T &upper, const T &invalid_value)
{
std::vector<T>::const_iterator it = vec.begin();
while (it != vec.end() && *it < value)
++it;
if(it != vec.end())
upper = *it;
else
upper = invalid_value;
if(it == vec.begin())
lower = invalid_value;
else
lower = *(--it);
}
Example of usage:
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(10);
int lower, upper;
find_enclosing_values(v, 4, lower, upper, -1);
std::cout<<"lower "<<lower<<" upper "<<upper<<std::endl;
If you have the ability to use some other data structure (not a vector), I'd suggest a B-tree. If you data is unchanging, I believe you can retrieve the result in constant time (logarithmic time at the worst).