How to iterate equal values with the standard library?How do you set, clear, and toggle a single bit?How do I iterate over the words of a string?How do I sort a vector of pairs based on the second element of the pair?How can I profile C++ code running on Linux?C++ sorting and keeping track of indexesC++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Iterator invalidation rulesHow to implement equal range “iterator”Resize vector given an iterator in C++Most 'functional' way to sum pairs of elements from a vector using C++17 or later?
Why do we need a bootloader separate than our application program in MCU's?
Why do Klingons use cloaking devices?
Can mxd files be under version control?
What is the addition in the re-released version of Avengers: Endgame?
Show that there are infinitely more problems than we will ever be able to compute
Apex Sleep: what is CPU penalty
Taking advantage when the HR forgets to communicate the rules
What is the fundamental difference between catching whales and hunting other animals?
Why did C++11 make std::string::data() add a null terminating character?
Can 4 Joy cons connect to the same Switch?
What is the maximum amount of diamond in one Minecraft game?
Bypass with wrong cvv of debit card and getting OTP
Is it possible that Curiosity measured its own methane or failed doing the spectrometry?
Implementing absolute value function in c
How can I define a very large matrix efficiently?
Can a wizard delay learning new spells from leveling up, and instead learn different spells later?
Could you sell yourself into slavery in the USA?
How can I effectively map a multi-level dungeon?
Do the 26 richest billionaires own as much wealth as the poorest 3.8 billion people?
Does Evolution Sage proliferate Blast Zone when played?
What is this arch-and-tower near a road?
What is the difference between a historical drama and a period drama?
Data normalization before or after train-test split?
What is the name of the technique when an element is repeated at different scales?
How to iterate equal values with the standard library?
How do you set, clear, and toggle a single bit?How do I iterate over the words of a string?How do I sort a vector of pairs based on the second element of the pair?How can I profile C++ code running on Linux?C++ sorting and keeping track of indexesC++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Iterator invalidation rulesHow to implement equal range “iterator”Resize vector given an iterator in C++Most 'functional' way to sum pairs of elements from a vector using C++17 or later?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
Suppose that I have a vector of something:
std::vector<Foo> v;
This vector is sorted, so equal elements are next to each other.
What is the best way to get all iterator pairs representing ranges with equal elements (using the standard library)?
while (v-is-not-processed)
iterator b = <begin-of-next-range-of-equal-elements>;
iterator e = <end-of-next-range-of-equal-elements>;
for (iterator i=b; i!=e; ++i)
// do something with i
I'd like to know, how to get values of b
and e
in the code above.
So, for example, if v
contains these numbers:
index 0 1 2 3 4 5 6 7 8 9
value 2 2 2 4 6 6 7 7 7 8
Then I'd like to have b
and e
point to elements in the loop:
iteration b e
1st 0 3
2nd 3 4
3rd 4 6
4th 6 9
5th 9 10
Is there an elegant way to solve this with the standard library?
c++ c++17
add a comment |
Suppose that I have a vector of something:
std::vector<Foo> v;
This vector is sorted, so equal elements are next to each other.
What is the best way to get all iterator pairs representing ranges with equal elements (using the standard library)?
while (v-is-not-processed)
iterator b = <begin-of-next-range-of-equal-elements>;
iterator e = <end-of-next-range-of-equal-elements>;
for (iterator i=b; i!=e; ++i)
// do something with i
I'd like to know, how to get values of b
and e
in the code above.
So, for example, if v
contains these numbers:
index 0 1 2 3 4 5 6 7 8 9
value 2 2 2 4 6 6 7 7 7 8
Then I'd like to have b
and e
point to elements in the loop:
iteration b e
1st 0 3
2nd 3 4
3rd 4 6
4th 6 9
5th 9 10
Is there an elegant way to solve this with the standard library?
c++ c++17
1
It should be noted the code in the question is not a good example of how this could be useful. Nothing is done withe
other than bounding the inner loop, and the inner loop could just as well be bounded by testing for a new value in elementi
. So any effort expended findinge
serves no purpose (unless computation of the “value” used to sortv
is so excessively expensive that a binary search fore
would be cheaper than testing each element as we go).
– Eric Postpischil
7 hours ago
@EricPostpischil: That's true. But even if we don't usee
for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially - or do you know some tricks to avoid it?).
– geza
7 hours ago
add a comment |
Suppose that I have a vector of something:
std::vector<Foo> v;
This vector is sorted, so equal elements are next to each other.
What is the best way to get all iterator pairs representing ranges with equal elements (using the standard library)?
while (v-is-not-processed)
iterator b = <begin-of-next-range-of-equal-elements>;
iterator e = <end-of-next-range-of-equal-elements>;
for (iterator i=b; i!=e; ++i)
// do something with i
I'd like to know, how to get values of b
and e
in the code above.
So, for example, if v
contains these numbers:
index 0 1 2 3 4 5 6 7 8 9
value 2 2 2 4 6 6 7 7 7 8
Then I'd like to have b
and e
point to elements in the loop:
iteration b e
1st 0 3
2nd 3 4
3rd 4 6
4th 6 9
5th 9 10
Is there an elegant way to solve this with the standard library?
c++ c++17
Suppose that I have a vector of something:
std::vector<Foo> v;
This vector is sorted, so equal elements are next to each other.
What is the best way to get all iterator pairs representing ranges with equal elements (using the standard library)?
while (v-is-not-processed)
iterator b = <begin-of-next-range-of-equal-elements>;
iterator e = <end-of-next-range-of-equal-elements>;
for (iterator i=b; i!=e; ++i)
// do something with i
I'd like to know, how to get values of b
and e
in the code above.
So, for example, if v
contains these numbers:
index 0 1 2 3 4 5 6 7 8 9
value 2 2 2 4 6 6 7 7 7 8
Then I'd like to have b
and e
point to elements in the loop:
iteration b e
1st 0 3
2nd 3 4
3rd 4 6
4th 6 9
5th 9 10
Is there an elegant way to solve this with the standard library?
c++ c++17
c++ c++17
asked 8 hours ago
gezageza
15k3 gold badges34 silver badges87 bronze badges
15k3 gold badges34 silver badges87 bronze badges
1
It should be noted the code in the question is not a good example of how this could be useful. Nothing is done withe
other than bounding the inner loop, and the inner loop could just as well be bounded by testing for a new value in elementi
. So any effort expended findinge
serves no purpose (unless computation of the “value” used to sortv
is so excessively expensive that a binary search fore
would be cheaper than testing each element as we go).
– Eric Postpischil
7 hours ago
@EricPostpischil: That's true. But even if we don't usee
for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially - or do you know some tricks to avoid it?).
– geza
7 hours ago
add a comment |
1
It should be noted the code in the question is not a good example of how this could be useful. Nothing is done withe
other than bounding the inner loop, and the inner loop could just as well be bounded by testing for a new value in elementi
. So any effort expended findinge
serves no purpose (unless computation of the “value” used to sortv
is so excessively expensive that a binary search fore
would be cheaper than testing each element as we go).
– Eric Postpischil
7 hours ago
@EricPostpischil: That's true. But even if we don't usee
for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially - or do you know some tricks to avoid it?).
– geza
7 hours ago
1
1
It should be noted the code in the question is not a good example of how this could be useful. Nothing is done with
e
other than bounding the inner loop, and the inner loop could just as well be bounded by testing for a new value in element i
. So any effort expended finding e
serves no purpose (unless computation of the “value” used to sort v
is so excessively expensive that a binary search for e
would be cheaper than testing each element as we go).– Eric Postpischil
7 hours ago
It should be noted the code in the question is not a good example of how this could be useful. Nothing is done with
e
other than bounding the inner loop, and the inner loop could just as well be bounded by testing for a new value in element i
. So any effort expended finding e
serves no purpose (unless computation of the “value” used to sort v
is so excessively expensive that a binary search for e
would be cheaper than testing each element as we go).– Eric Postpischil
7 hours ago
@EricPostpischil: That's true. But even if we don't use
e
for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially - or do you know some tricks to avoid it?).– geza
7 hours ago
@EricPostpischil: That's true. But even if we don't use
e
for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially - or do you know some tricks to avoid it?).– geza
7 hours ago
add a comment |
4 Answers
4
active
oldest
votes
You can use std::upper_bound
to get the iterator to the "next" value. Since std::upper_bound
returns an iterator to the first element greater than that value provided, if you provide the value of the current element, it will give you an iterator that will be one past the end of the current value. That would give you a loop like
iterator it = v.begin();
while (it != v.end())
iterator b = it;
iterator e = std::upper_bound(it, v.end(), *it);
for (iterator i=b; i!=e; ++i)
// do something with i
it = e; // need this so the loop starts on the next value
The only problem is thatstd::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.
– geza
8 hours ago
2
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
2
@geza If you want to do a linear traversal instead then you can replacestd::upper_bound(it, v.end(), *it);
withstd::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.
– NathanOliver
8 hours ago
add a comment |
This is basically Range v3's group_by
: group_by(v, std::equal_to)
. It doesn't exist in the C++17 standard library, but we can write our own rough equivalent:
template <typename FwdIter, typename BinaryPred, typename ForEach>
void for_each_equal_range(FwdIter first, FwdIter last, BinaryPred is_equal, ForEach f)
while (first != last)
auto next_unequal = std::find_if_not(std::next(first), last,
[&] (auto const& element) return is_equal(*first, element); );
f(first, next_unequal);
first = next_unequal;
Usage:
for_each_equal_range(v.begin(), v.end(), std::equal_to, [&] (auto first, auto last)
for (; first != last; ++first)
// Do something with each element.
);
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
add a comment |
You are looking for std::equal_range.
Returns a range containing all elements equivalent to value in the
range [first, last).
Something like the following should work. (Untested)
iterator it = v.begin();
while (it != v.end())
auto[b, e] = std::equal_range(it, v.end(), *it);
// do something with [b, e)
it = e; // need for the beginning of next std::equal_range
2
This does some extra work to find the lower-bound of the range when we know that it's justit
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead ofstd::equal_range
).
– Justin
7 hours ago
1
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
add a comment |
But even if we don't use e for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially [...])
Depends on how you interpret 'handling last range specially':
auto begin = v.begin();
// we might need some initialization for whatever on *begin...
for(Iterator i = begin + 1; ; ++i)
No special handling for last range – solely, possibly needing the initialization code twice...
Nested-loop-approach:
auto begin = v.begin();
for(;;)
// initialize first/next range using *begin
for(Iterator i = begin + 1; ; ++i)
LOOP_EXIT:
// go on
// if nothing left to do in function, we might prefer returning over going to...
More elegant? Admitted, I'm in doubt myself... Both approaches avoid iterating over the same range twice (first for finding the end, then the actual iteration), though. And if we make our own library function from:
template <typename Iterator, typename RangeInitializer, typename ElementHandler>
void iterateOverEqualRanges
(
Iterator begin, Iterator end,
RangeInitializer ri, ElementHandler eh
)
// the one of the two approaches you like better
// or your own variation of...
we could then use it like:
std::vector<...> v;
iterateOverEqualRanges
(
v.begin(), v.end(),
[] (auto begin) /* ... */ ,
[] (auto current) /* ... */
);
Now finally, it looks similiar to e. g. std::for_each
, doesn't it?
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56859749%2fhow-to-iterate-equal-values-with-the-standard-library%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can use std::upper_bound
to get the iterator to the "next" value. Since std::upper_bound
returns an iterator to the first element greater than that value provided, if you provide the value of the current element, it will give you an iterator that will be one past the end of the current value. That would give you a loop like
iterator it = v.begin();
while (it != v.end())
iterator b = it;
iterator e = std::upper_bound(it, v.end(), *it);
for (iterator i=b; i!=e; ++i)
// do something with i
it = e; // need this so the loop starts on the next value
The only problem is thatstd::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.
– geza
8 hours ago
2
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
2
@geza If you want to do a linear traversal instead then you can replacestd::upper_bound(it, v.end(), *it);
withstd::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.
– NathanOliver
8 hours ago
add a comment |
You can use std::upper_bound
to get the iterator to the "next" value. Since std::upper_bound
returns an iterator to the first element greater than that value provided, if you provide the value of the current element, it will give you an iterator that will be one past the end of the current value. That would give you a loop like
iterator it = v.begin();
while (it != v.end())
iterator b = it;
iterator e = std::upper_bound(it, v.end(), *it);
for (iterator i=b; i!=e; ++i)
// do something with i
it = e; // need this so the loop starts on the next value
The only problem is thatstd::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.
– geza
8 hours ago
2
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
2
@geza If you want to do a linear traversal instead then you can replacestd::upper_bound(it, v.end(), *it);
withstd::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.
– NathanOliver
8 hours ago
add a comment |
You can use std::upper_bound
to get the iterator to the "next" value. Since std::upper_bound
returns an iterator to the first element greater than that value provided, if you provide the value of the current element, it will give you an iterator that will be one past the end of the current value. That would give you a loop like
iterator it = v.begin();
while (it != v.end())
iterator b = it;
iterator e = std::upper_bound(it, v.end(), *it);
for (iterator i=b; i!=e; ++i)
// do something with i
it = e; // need this so the loop starts on the next value
You can use std::upper_bound
to get the iterator to the "next" value. Since std::upper_bound
returns an iterator to the first element greater than that value provided, if you provide the value of the current element, it will give you an iterator that will be one past the end of the current value. That would give you a loop like
iterator it = v.begin();
while (it != v.end())
iterator b = it;
iterator e = std::upper_bound(it, v.end(), *it);
for (iterator i=b; i!=e; ++i)
// do something with i
it = e; // need this so the loop starts on the next value
edited 7 hours ago
Justin
14.4k9 gold badges60 silver badges102 bronze badges
14.4k9 gold badges60 silver badges102 bronze badges
answered 8 hours ago
NathanOliverNathanOliver
107k19 gold badges159 silver badges236 bronze badges
107k19 gold badges159 silver badges236 bronze badges
The only problem is thatstd::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.
– geza
8 hours ago
2
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
2
@geza If you want to do a linear traversal instead then you can replacestd::upper_bound(it, v.end(), *it);
withstd::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.
– NathanOliver
8 hours ago
add a comment |
The only problem is thatstd::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.
– geza
8 hours ago
2
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
2
@geza If you want to do a linear traversal instead then you can replacestd::upper_bound(it, v.end(), *it);
withstd::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.
– NathanOliver
8 hours ago
The only problem is that
std::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.– geza
8 hours ago
The only problem is that
std::upper_bound
does a little bit more, because it has to find the element with binary search. But in my case, this is unneeded.– geza
8 hours ago
2
2
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
This makes sense if the subranges of equal elements are large. If they are small, you waste effort doing a binary search over the entire range, when a linear search could find the next element faster (and with better cache locality).
– Justin
8 hours ago
2
2
@geza If you want to do a linear traversal instead then you can replace
std::upper_bound(it, v.end(), *it);
with std::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.– NathanOliver
8 hours ago
@geza If you want to do a linear traversal instead then you can replace
std::upper_bound(it, v.end(), *it);
with std::find_if(it, v.end(), [=](auto e) return *it != e; );
. Depending on the data this could definitely be faster.– NathanOliver
8 hours ago
add a comment |
This is basically Range v3's group_by
: group_by(v, std::equal_to)
. It doesn't exist in the C++17 standard library, but we can write our own rough equivalent:
template <typename FwdIter, typename BinaryPred, typename ForEach>
void for_each_equal_range(FwdIter first, FwdIter last, BinaryPred is_equal, ForEach f)
while (first != last)
auto next_unequal = std::find_if_not(std::next(first), last,
[&] (auto const& element) return is_equal(*first, element); );
f(first, next_unequal);
first = next_unequal;
Usage:
for_each_equal_range(v.begin(), v.end(), std::equal_to, [&] (auto first, auto last)
for (; first != last; ++first)
// Do something with each element.
);
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
add a comment |
This is basically Range v3's group_by
: group_by(v, std::equal_to)
. It doesn't exist in the C++17 standard library, but we can write our own rough equivalent:
template <typename FwdIter, typename BinaryPred, typename ForEach>
void for_each_equal_range(FwdIter first, FwdIter last, BinaryPred is_equal, ForEach f)
while (first != last)
auto next_unequal = std::find_if_not(std::next(first), last,
[&] (auto const& element) return is_equal(*first, element); );
f(first, next_unequal);
first = next_unequal;
Usage:
for_each_equal_range(v.begin(), v.end(), std::equal_to, [&] (auto first, auto last)
for (; first != last; ++first)
// Do something with each element.
);
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
add a comment |
This is basically Range v3's group_by
: group_by(v, std::equal_to)
. It doesn't exist in the C++17 standard library, but we can write our own rough equivalent:
template <typename FwdIter, typename BinaryPred, typename ForEach>
void for_each_equal_range(FwdIter first, FwdIter last, BinaryPred is_equal, ForEach f)
while (first != last)
auto next_unequal = std::find_if_not(std::next(first), last,
[&] (auto const& element) return is_equal(*first, element); );
f(first, next_unequal);
first = next_unequal;
Usage:
for_each_equal_range(v.begin(), v.end(), std::equal_to, [&] (auto first, auto last)
for (; first != last; ++first)
// Do something with each element.
);
This is basically Range v3's group_by
: group_by(v, std::equal_to)
. It doesn't exist in the C++17 standard library, but we can write our own rough equivalent:
template <typename FwdIter, typename BinaryPred, typename ForEach>
void for_each_equal_range(FwdIter first, FwdIter last, BinaryPred is_equal, ForEach f)
while (first != last)
auto next_unequal = std::find_if_not(std::next(first), last,
[&] (auto const& element) return is_equal(*first, element); );
f(first, next_unequal);
first = next_unequal;
Usage:
for_each_equal_range(v.begin(), v.end(), std::equal_to, [&] (auto first, auto last)
for (; first != last; ++first)
// Do something with each element.
);
edited 8 hours ago
answered 8 hours ago
JustinJustin
14.4k9 gold badges60 silver badges102 bronze badges
14.4k9 gold badges60 silver badges102 bronze badges
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
add a comment |
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.
– Justin
8 hours ago
add a comment |
You are looking for std::equal_range.
Returns a range containing all elements equivalent to value in the
range [first, last).
Something like the following should work. (Untested)
iterator it = v.begin();
while (it != v.end())
auto[b, e] = std::equal_range(it, v.end(), *it);
// do something with [b, e)
it = e; // need for the beginning of next std::equal_range
2
This does some extra work to find the lower-bound of the range when we know that it's justit
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead ofstd::equal_range
).
– Justin
7 hours ago
1
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
add a comment |
You are looking for std::equal_range.
Returns a range containing all elements equivalent to value in the
range [first, last).
Something like the following should work. (Untested)
iterator it = v.begin();
while (it != v.end())
auto[b, e] = std::equal_range(it, v.end(), *it);
// do something with [b, e)
it = e; // need for the beginning of next std::equal_range
2
This does some extra work to find the lower-bound of the range when we know that it's justit
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead ofstd::equal_range
).
– Justin
7 hours ago
1
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
add a comment |
You are looking for std::equal_range.
Returns a range containing all elements equivalent to value in the
range [first, last).
Something like the following should work. (Untested)
iterator it = v.begin();
while (it != v.end())
auto[b, e] = std::equal_range(it, v.end(), *it);
// do something with [b, e)
it = e; // need for the beginning of next std::equal_range
You are looking for std::equal_range.
Returns a range containing all elements equivalent to value in the
range [first, last).
Something like the following should work. (Untested)
iterator it = v.begin();
while (it != v.end())
auto[b, e] = std::equal_range(it, v.end(), *it);
// do something with [b, e)
it = e; // need for the beginning of next std::equal_range
edited 7 hours ago
Justin
14.4k9 gold badges60 silver badges102 bronze badges
14.4k9 gold badges60 silver badges102 bronze badges
answered 8 hours ago
JeJoJeJo
6,7463 gold badges12 silver badges34 bronze badges
6,7463 gold badges12 silver badges34 bronze badges
2
This does some extra work to find the lower-bound of the range when we know that it's justit
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead ofstd::equal_range
).
– Justin
7 hours ago
1
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
add a comment |
2
This does some extra work to find the lower-bound of the range when we know that it's justit
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead ofstd::equal_range
).
– Justin
7 hours ago
1
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
2
2
This does some extra work to find the lower-bound of the range when we know that it's just
it
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead of std::equal_range
).– Justin
7 hours ago
This does some extra work to find the lower-bound of the range when we know that it's just
it
, but at that point, we'd be the same as NathanOliver's answer (std::upper_bound
instead of std::equal_range
).– Justin
7 hours ago
1
1
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
@Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.
– JeJo
7 hours ago
add a comment |
But even if we don't use e for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially [...])
Depends on how you interpret 'handling last range specially':
auto begin = v.begin();
// we might need some initialization for whatever on *begin...
for(Iterator i = begin + 1; ; ++i)
No special handling for last range – solely, possibly needing the initialization code twice...
Nested-loop-approach:
auto begin = v.begin();
for(;;)
// initialize first/next range using *begin
for(Iterator i = begin + 1; ; ++i)
LOOP_EXIT:
// go on
// if nothing left to do in function, we might prefer returning over going to...
More elegant? Admitted, I'm in doubt myself... Both approaches avoid iterating over the same range twice (first for finding the end, then the actual iteration), though. And if we make our own library function from:
template <typename Iterator, typename RangeInitializer, typename ElementHandler>
void iterateOverEqualRanges
(
Iterator begin, Iterator end,
RangeInitializer ri, ElementHandler eh
)
// the one of the two approaches you like better
// or your own variation of...
we could then use it like:
std::vector<...> v;
iterateOverEqualRanges
(
v.begin(), v.end(),
[] (auto begin) /* ... */ ,
[] (auto current) /* ... */
);
Now finally, it looks similiar to e. g. std::for_each
, doesn't it?
add a comment |
But even if we don't use e for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially [...])
Depends on how you interpret 'handling last range specially':
auto begin = v.begin();
// we might need some initialization for whatever on *begin...
for(Iterator i = begin + 1; ; ++i)
No special handling for last range – solely, possibly needing the initialization code twice...
Nested-loop-approach:
auto begin = v.begin();
for(;;)
// initialize first/next range using *begin
for(Iterator i = begin + 1; ; ++i)
LOOP_EXIT:
// go on
// if nothing left to do in function, we might prefer returning over going to...
More elegant? Admitted, I'm in doubt myself... Both approaches avoid iterating over the same range twice (first for finding the end, then the actual iteration), though. And if we make our own library function from:
template <typename Iterator, typename RangeInitializer, typename ElementHandler>
void iterateOverEqualRanges
(
Iterator begin, Iterator end,
RangeInitializer ri, ElementHandler eh
)
// the one of the two approaches you like better
// or your own variation of...
we could then use it like:
std::vector<...> v;
iterateOverEqualRanges
(
v.begin(), v.end(),
[] (auto begin) /* ... */ ,
[] (auto current) /* ... */
);
Now finally, it looks similiar to e. g. std::for_each
, doesn't it?
add a comment |
But even if we don't use e for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially [...])
Depends on how you interpret 'handling last range specially':
auto begin = v.begin();
// we might need some initialization for whatever on *begin...
for(Iterator i = begin + 1; ; ++i)
No special handling for last range – solely, possibly needing the initialization code twice...
Nested-loop-approach:
auto begin = v.begin();
for(;;)
// initialize first/next range using *begin
for(Iterator i = begin + 1; ; ++i)
LOOP_EXIT:
// go on
// if nothing left to do in function, we might prefer returning over going to...
More elegant? Admitted, I'm in doubt myself... Both approaches avoid iterating over the same range twice (first for finding the end, then the actual iteration), though. And if we make our own library function from:
template <typename Iterator, typename RangeInitializer, typename ElementHandler>
void iterateOverEqualRanges
(
Iterator begin, Iterator end,
RangeInitializer ri, ElementHandler eh
)
// the one of the two approaches you like better
// or your own variation of...
we could then use it like:
std::vector<...> v;
iterateOverEqualRanges
(
v.begin(), v.end(),
[] (auto begin) /* ... */ ,
[] (auto current) /* ... */
);
Now finally, it looks similiar to e. g. std::for_each
, doesn't it?
But even if we don't use e for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially [...])
Depends on how you interpret 'handling last range specially':
auto begin = v.begin();
// we might need some initialization for whatever on *begin...
for(Iterator i = begin + 1; ; ++i)
No special handling for last range – solely, possibly needing the initialization code twice...
Nested-loop-approach:
auto begin = v.begin();
for(;;)
// initialize first/next range using *begin
for(Iterator i = begin + 1; ; ++i)
LOOP_EXIT:
// go on
// if nothing left to do in function, we might prefer returning over going to...
More elegant? Admitted, I'm in doubt myself... Both approaches avoid iterating over the same range twice (first for finding the end, then the actual iteration), though. And if we make our own library function from:
template <typename Iterator, typename RangeInitializer, typename ElementHandler>
void iterateOverEqualRanges
(
Iterator begin, Iterator end,
RangeInitializer ri, ElementHandler eh
)
// the one of the two approaches you like better
// or your own variation of...
we could then use it like:
std::vector<...> v;
iterateOverEqualRanges
(
v.begin(), v.end(),
[] (auto begin) /* ... */ ,
[] (auto current) /* ... */
);
Now finally, it looks similiar to e. g. std::for_each
, doesn't it?
edited 7 hours ago
answered 7 hours ago
AconcaguaAconcagua
14.9k3 gold badges24 silver badges46 bronze badges
14.9k3 gold badges24 silver badges46 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56859749%2fhow-to-iterate-equal-values-with-the-standard-library%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
It should be noted the code in the question is not a good example of how this could be useful. Nothing is done with
e
other than bounding the inner loop, and the inner loop could just as well be bounded by testing for a new value in elementi
. So any effort expended findinge
serves no purpose (unless computation of the “value” used to sortv
is so excessively expensive that a binary search fore
would be cheaper than testing each element as we go).– Eric Postpischil
7 hours ago
@EricPostpischil: That's true. But even if we don't use
e
for anything, this formulation is convenient, it's harder to make an error. The other way (to check for changing values) is more tedious (as we need to handle the last range specially - or do you know some tricks to avoid it?).– geza
7 hours ago