How do I 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 check if an array includes an object in JavaScript?How do I sort a vector of pairs based on the second element of the pair?How to convert std::string to lower case?What's the difference between “STL” and “C++ Standard Library”?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Iterator invalidation rulesHow to pair socks from a pile efficiently?How to implement equal range “iterator”

What was the definition of "set" that resulted in Russell's Paradox

Is there any word for "disobedience to God"?

Referring to different instances of the same character in time travel

Terry Pratchett book with a lawyer dragon and sheep

Why isn't pressure filtration popular compared to vacuum filtration?

If a non-friend comes across my Steam Wishlist, how easily can he gift me one of the games?

Why do people keep referring to Leia as Princess Leia, even after the destruction of Alderaan?

What steps should I take to lawfully visit the United States as a tourist immediately after visiting on a B-1 visa?

Integer Lists of Noah

How to md5 a list of filepaths contained in a file?

How did the hit man miss?

Professor falsely accusing me of cheating in a class he does not teach, 2 months after end of the class. What precautions should I take?

What's the point of having a RAID 1 configuration over incremental backups to a secondary drive?

Received a dinner invitation through my employer's email, is it ok to attend?

Generating random numbers that keep a minimum distance

Constructive proof of existence of free algebras for infinitary equational theories

Combining latex input and sed

Credit score and financing new car

Multiple DUI convictions 12 years ago. Do I disclose if I know they will do a background check?

Machine learning and operations research projects

Why were Er and Onan punished if they were under 20?

Why did Harry Potter get a bedroom?

For a hashing function like MD5, how similar can two plaintext strings be and still generate the same hash?

What is the job of the acoustic cavities inside the main combustion chamber?



How do I 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 check if an array includes an object in JavaScript?How do I sort a vector of pairs based on the second element of the pair?How to convert std::string to lower case?What's the difference between “STL” and “C++ Standard Library”?C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?Iterator invalidation rulesHow to pair socks from a pile efficiently?How to implement equal range “iterator”






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








30















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?










share|improve this question



















  • 5





    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
    Jul 2 at 21:09












  • @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
    Jul 2 at 21:22











  • @geza No special treatment would be required for the last range.

    – Walter
    22 hours ago

















30















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?










share|improve this question



















  • 5





    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
    Jul 2 at 21:09












  • @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
    Jul 2 at 21:22











  • @geza No special treatment would be required for the last range.

    – Walter
    22 hours ago













30












30








30


1






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?










share|improve this question
















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++ algorithm c++17 c++-standard-library iterator-range






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 3 at 16:18









JeJo

7,2913 gold badges13 silver badges40 bronze badges




7,2913 gold badges13 silver badges40 bronze badges










asked Jul 2 at 20:38









gezageza

15.1k3 gold badges35 silver badges89 bronze badges




15.1k3 gold badges35 silver badges89 bronze badges







  • 5





    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
    Jul 2 at 21:09












  • @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
    Jul 2 at 21:22











  • @geza No special treatment would be required for the last range.

    – Walter
    22 hours ago












  • 5





    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
    Jul 2 at 21:09












  • @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
    Jul 2 at 21:22











  • @geza No special treatment would be required for the last range.

    – Walter
    22 hours ago







5




5





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
Jul 2 at 21:09






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
Jul 2 at 21:09














@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
Jul 2 at 21:22





@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
Jul 2 at 21:22













@geza No special treatment would be required for the last range.

– Walter
22 hours ago





@geza No special treatment would be required for the last range.

– Walter
22 hours ago












6 Answers
6






active

oldest

votes


















22














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.

);





share|improve this answer




















  • 1





    If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

    – Justin
    Jul 2 at 20:52












  • I like this solution the most, as its usage is the clearest one.

    – geza
    Jul 3 at 6:44


















25














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






share|improve this answer




















  • 1





    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
    Jul 2 at 20:55






  • 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
    Jul 2 at 20:55






  • 4





    @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
    Jul 2 at 20:59











  • +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

    – geza
    Jul 3 at 6:47


















17














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.



auto it = v.begin();
while (it != v.end())

auto [b, e] = std::equal_range(it, v.end(), *it);
for (; b != e; ++b) /* do something in the range[b, e) */
it = e; // need for the beginning of next std::equal_range




Remark: Even though this will be an intuitive approach, the std::equal_range obtains its first and second iterators(i.e b and e) with the help of std::lower_bound and std::upper_bound, which makes this approche slightly inefficient. Since, the first iterator could be easily accessible for the OP's case, calling std::upper_bound for second iterator only neccesarry(as shown by @NathanOliver 's answer).






share|improve this answer




















  • 3





    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
    Jul 2 at 21:09







  • 2





    @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

    – JeJo
    Jul 2 at 21:12











  • +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

    – geza
    Jul 3 at 6:48


















8














If your ranges of equal values is short, then std::adjacent_find would work well:



for (auto it = v.begin(); it != v.end();) 
auto next = std::adjacent_find(it, v.end(), std::not_equal_to<Foo>());
for(; it != next; ++it)





You can also substitute a lambda for std::not_equal_to if you wish.






share|improve this answer


















  • 3





    Nice trick of using std::adjacent_find to find the boundary!

    – geza
    Jul 3 at 6:49



















6















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)
*i != *begin)

// handle range single element of range [begin, ???);
if(i == v.end())
break;
begin = i;
// re-initialize next range




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?






share|improve this answer

























  • Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

    – geza
    Jul 3 at 6:52



















0














for(auto b=v.begin(), i=b, e=v.end(); i!=e; b=i) 
// initialise the 'Do something' code for another range
for(; i!=e && *i==*b; ++i)
// Do something with i







share|improve this answer

























    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
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56859749%2fhow-do-i-iterate-equal-values-with-the-standard-library%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    6 Answers
    6






    active

    oldest

    votes








    6 Answers
    6






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    22














    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.

    );





    share|improve this answer




















    • 1





      If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

      – Justin
      Jul 2 at 20:52












    • I like this solution the most, as its usage is the clearest one.

      – geza
      Jul 3 at 6:44















    22














    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.

    );





    share|improve this answer




















    • 1





      If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

      – Justin
      Jul 2 at 20:52












    • I like this solution the most, as its usage is the clearest one.

      – geza
      Jul 3 at 6:44













    22












    22








    22







    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.

    );





    share|improve this answer















    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.

    );






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 2 at 21:01

























    answered Jul 2 at 20:51









    JustinJustin

    14.6k9 gold badges60 silver badges104 bronze badges




    14.6k9 gold badges60 silver badges104 bronze badges







    • 1





      If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

      – Justin
      Jul 2 at 20:52












    • I like this solution the most, as its usage is the clearest one.

      – geza
      Jul 3 at 6:44












    • 1





      If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

      – Justin
      Jul 2 at 20:52












    • I like this solution the most, as its usage is the clearest one.

      – geza
      Jul 3 at 6:44







    1




    1





    If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

    – Justin
    Jul 2 at 20:52






    If you know that these subranges of equal elements are large, you may benefit by probing through some sort of binary search.

    – Justin
    Jul 2 at 20:52














    I like this solution the most, as its usage is the clearest one.

    – geza
    Jul 3 at 6:44





    I like this solution the most, as its usage is the clearest one.

    – geza
    Jul 3 at 6:44













    25














    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






    share|improve this answer




















    • 1





      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
      Jul 2 at 20:55






    • 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
      Jul 2 at 20:55






    • 4





      @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
      Jul 2 at 20:59











    • +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

      – geza
      Jul 3 at 6:47















    25














    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






    share|improve this answer




















    • 1





      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
      Jul 2 at 20:55






    • 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
      Jul 2 at 20:55






    • 4





      @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
      Jul 2 at 20:59











    • +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

      – geza
      Jul 3 at 6:47













    25












    25








    25







    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






    share|improve this answer















    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







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 2 at 21:12









    Justin

    14.6k9 gold badges60 silver badges104 bronze badges




    14.6k9 gold badges60 silver badges104 bronze badges










    answered Jul 2 at 20:48









    NathanOliverNathanOliver

    108k19 gold badges160 silver badges238 bronze badges




    108k19 gold badges160 silver badges238 bronze badges







    • 1





      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
      Jul 2 at 20:55






    • 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
      Jul 2 at 20:55






    • 4





      @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
      Jul 2 at 20:59











    • +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

      – geza
      Jul 3 at 6:47












    • 1





      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
      Jul 2 at 20:55






    • 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
      Jul 2 at 20:55






    • 4





      @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
      Jul 2 at 20:59











    • +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

      – geza
      Jul 3 at 6:47







    1




    1





    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
    Jul 2 at 20:55





    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
    Jul 2 at 20:55




    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
    Jul 2 at 20:55





    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
    Jul 2 at 20:55




    4




    4





    @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
    Jul 2 at 20:59





    @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
    Jul 2 at 20:59













    +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

    – geza
    Jul 3 at 6:47





    +1, thanks, but I accepted Justin's solution, as it is a little bit more clear at the usage (I mean, the algorithm has a name, so it is easier to understand, what the code does - but of course, your variation can be modified this way as well, your solution basically the same).

    – geza
    Jul 3 at 6:47











    17














    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.



    auto it = v.begin();
    while (it != v.end())

    auto [b, e] = std::equal_range(it, v.end(), *it);
    for (; b != e; ++b) /* do something in the range[b, e) */
    it = e; // need for the beginning of next std::equal_range




    Remark: Even though this will be an intuitive approach, the std::equal_range obtains its first and second iterators(i.e b and e) with the help of std::lower_bound and std::upper_bound, which makes this approche slightly inefficient. Since, the first iterator could be easily accessible for the OP's case, calling std::upper_bound for second iterator only neccesarry(as shown by @NathanOliver 's answer).






    share|improve this answer




















    • 3





      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
      Jul 2 at 21:09







    • 2





      @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

      – JeJo
      Jul 2 at 21:12











    • +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

      – geza
      Jul 3 at 6:48















    17














    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.



    auto it = v.begin();
    while (it != v.end())

    auto [b, e] = std::equal_range(it, v.end(), *it);
    for (; b != e; ++b) /* do something in the range[b, e) */
    it = e; // need for the beginning of next std::equal_range




    Remark: Even though this will be an intuitive approach, the std::equal_range obtains its first and second iterators(i.e b and e) with the help of std::lower_bound and std::upper_bound, which makes this approche slightly inefficient. Since, the first iterator could be easily accessible for the OP's case, calling std::upper_bound for second iterator only neccesarry(as shown by @NathanOliver 's answer).






    share|improve this answer




















    • 3





      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
      Jul 2 at 21:09







    • 2





      @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

      – JeJo
      Jul 2 at 21:12











    • +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

      – geza
      Jul 3 at 6:48













    17












    17








    17







    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.



    auto it = v.begin();
    while (it != v.end())

    auto [b, e] = std::equal_range(it, v.end(), *it);
    for (; b != e; ++b) /* do something in the range[b, e) */
    it = e; // need for the beginning of next std::equal_range




    Remark: Even though this will be an intuitive approach, the std::equal_range obtains its first and second iterators(i.e b and e) with the help of std::lower_bound and std::upper_bound, which makes this approche slightly inefficient. Since, the first iterator could be easily accessible for the OP's case, calling std::upper_bound for second iterator only neccesarry(as shown by @NathanOliver 's answer).






    share|improve this answer















    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.



    auto it = v.begin();
    while (it != v.end())

    auto [b, e] = std::equal_range(it, v.end(), *it);
    for (; b != e; ++b) /* do something in the range[b, e) */
    it = e; // need for the beginning of next std::equal_range




    Remark: Even though this will be an intuitive approach, the std::equal_range obtains its first and second iterators(i.e b and e) with the help of std::lower_bound and std::upper_bound, which makes this approche slightly inefficient. Since, the first iterator could be easily accessible for the OP's case, calling std::upper_bound for second iterator only neccesarry(as shown by @NathanOliver 's answer).







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 6 at 11:55

























    answered Jul 2 at 20:56









    JeJoJeJo

    7,2913 gold badges13 silver badges40 bronze badges




    7,2913 gold badges13 silver badges40 bronze badges







    • 3





      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
      Jul 2 at 21:09







    • 2





      @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

      – JeJo
      Jul 2 at 21:12











    • +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

      – geza
      Jul 3 at 6:48












    • 3





      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
      Jul 2 at 21:09







    • 2





      @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

      – JeJo
      Jul 2 at 21:12











    • +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

      – geza
      Jul 3 at 6:48







    3




    3





    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
    Jul 2 at 21:09






    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
    Jul 2 at 21:09





    2




    2





    @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

    – JeJo
    Jul 2 at 21:12





    @Justin Agreed. Maybe a slight advantage: less typing due to structured binding possibility.

    – JeJo
    Jul 2 at 21:12













    +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

    – geza
    Jul 3 at 6:48





    +1, but I've accepted Justin's solution, as while this is the shortest version (and easy to understand without adding a name), has the little problem of unnecessary work done by std::equal_range.

    – geza
    Jul 3 at 6:48











    8














    If your ranges of equal values is short, then std::adjacent_find would work well:



    for (auto it = v.begin(); it != v.end();) 
    auto next = std::adjacent_find(it, v.end(), std::not_equal_to<Foo>());
    for(; it != next; ++it)





    You can also substitute a lambda for std::not_equal_to if you wish.






    share|improve this answer


















    • 3





      Nice trick of using std::adjacent_find to find the boundary!

      – geza
      Jul 3 at 6:49
















    8














    If your ranges of equal values is short, then std::adjacent_find would work well:



    for (auto it = v.begin(); it != v.end();) 
    auto next = std::adjacent_find(it, v.end(), std::not_equal_to<Foo>());
    for(; it != next; ++it)





    You can also substitute a lambda for std::not_equal_to if you wish.






    share|improve this answer


















    • 3





      Nice trick of using std::adjacent_find to find the boundary!

      – geza
      Jul 3 at 6:49














    8












    8








    8







    If your ranges of equal values is short, then std::adjacent_find would work well:



    for (auto it = v.begin(); it != v.end();) 
    auto next = std::adjacent_find(it, v.end(), std::not_equal_to<Foo>());
    for(; it != next; ++it)





    You can also substitute a lambda for std::not_equal_to if you wish.






    share|improve this answer













    If your ranges of equal values is short, then std::adjacent_find would work well:



    for (auto it = v.begin(); it != v.end();) 
    auto next = std::adjacent_find(it, v.end(), std::not_equal_to<Foo>());
    for(; it != next; ++it)





    You can also substitute a lambda for std::not_equal_to if you wish.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Jul 3 at 6:21









    KyleKyle

    4,5652 gold badges20 silver badges35 bronze badges




    4,5652 gold badges20 silver badges35 bronze badges







    • 3





      Nice trick of using std::adjacent_find to find the boundary!

      – geza
      Jul 3 at 6:49













    • 3





      Nice trick of using std::adjacent_find to find the boundary!

      – geza
      Jul 3 at 6:49








    3




    3





    Nice trick of using std::adjacent_find to find the boundary!

    – geza
    Jul 3 at 6:49






    Nice trick of using std::adjacent_find to find the boundary!

    – geza
    Jul 3 at 6:49












    6















    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)
    *i != *begin)

    // handle range single element of range [begin, ???);
    if(i == v.end())
    break;
    begin = i;
    // re-initialize next range




    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?






    share|improve this answer

























    • Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

      – geza
      Jul 3 at 6:52
















    6















    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)
    *i != *begin)

    // handle range single element of range [begin, ???);
    if(i == v.end())
    break;
    begin = i;
    // re-initialize next range




    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?






    share|improve this answer

























    • Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

      – geza
      Jul 3 at 6:52














    6












    6








    6








    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)
    *i != *begin)

    // handle range single element of range [begin, ???);
    if(i == v.end())
    break;
    begin = i;
    // re-initialize next range




    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?






    share|improve this answer
















    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)
    *i != *begin)

    // handle range single element of range [begin, ???);
    if(i == v.end())
    break;
    begin = i;
    // re-initialize next range




    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?







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Jul 2 at 21:57

























    answered Jul 2 at 21:34









    AconcaguaAconcagua

    15.1k3 gold badges24 silver badges46 bronze badges




    15.1k3 gold badges24 silver badges46 bronze badges












    • Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

      – geza
      Jul 3 at 6:52


















    • Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

      – geza
      Jul 3 at 6:52

















    Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

    – geza
    Jul 3 at 6:52






    Thanks for the solution, I like that it doesn't need double iteration on the elements. By "handling last range specially" I meant that we need to check it somehow. Even by doing the i == v.end() twice.

    – geza
    Jul 3 at 6:52












    0














    for(auto b=v.begin(), i=b, e=v.end(); i!=e; b=i) 
    // initialise the 'Do something' code for another range
    for(; i!=e && *i==*b; ++i)
    // Do something with i







    share|improve this answer



























      0














      for(auto b=v.begin(), i=b, e=v.end(); i!=e; b=i) 
      // initialise the 'Do something' code for another range
      for(; i!=e && *i==*b; ++i)
      // Do something with i







      share|improve this answer

























        0












        0








        0







        for(auto b=v.begin(), i=b, e=v.end(); i!=e; b=i) 
        // initialise the 'Do something' code for another range
        for(; i!=e && *i==*b; ++i)
        // Do something with i







        share|improve this answer













        for(auto b=v.begin(), i=b, e=v.end(); i!=e; b=i) 
        // initialise the 'Do something' code for another range
        for(; i!=e && *i==*b; ++i)
        // Do something with i








        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 22 hours ago









        WalterWalter

        28.8k15 gold badges78 silver badges157 bronze badges




        28.8k15 gold badges78 silver badges157 bronze badges



























            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56859749%2fhow-do-i-iterate-equal-values-with-the-standard-library%23new-answer', 'question_page');

            );

            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







            Popular posts from this blog

            Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

            Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

            Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form