-1

I have a set of words (BELLOW, CELLO, HAAF, HABIT, HADAL, HAIR, HELLO, HELP, RABIT) stored in std::set datastructure.

  1. From the above set DS, I want to extract words which starts(0th index) with 'H' and store it other container(say std::setstd::string ctr). Now, ctr will have - HAAF, HABIT, HADAL, HAIR, HELLO, HELP

  2. Now, I want to fetch the words which has the second letter(1st Index) as 'A' from the container ctr. Now, ctr will have - HAAF, HABIT, HADAL, HAIR

  3. I want to fetch the words which has the letter 'A' in any index other than 0th & 1st Indices. Basically, I don't want to check the string 0th and 1st positions.

    Now, ctr will have - HAAF, HADAL

I'm not sure how to do the 3rd step.

#include <iostream>
#include <set>

int main()
{
    std::set<std::string> words = {"BELLOW", "CELLO",  "HAAF", 
                                   "HABIT",  "HADAL", "HAIR",
                                   "HELLO", "HELP", "RABIT"};
    for (const std::string& s : words) {
        std::cout << s << std::endl;    
    }
    
    std::set<std::string> etr;
    
    /* Extract words start with letter 'H' */
    for (const std::string& s : words) {
        if (s[0] == 'H') {
           //std::cout << s << std::endl;  
           etr.insert(s);
        }
    }
    
    std::cout << std::endl;
    
    for (const std::string& s : etr) {
        std::cout << s << std::endl;    
    }
    
    std::set<std::string> etr2;
    
    /* Extract words start with letter 'H' & 
       second letter as 'A' */
    for (const std::string& s : etr) {
        if (s[1] == 'A') {
           //std::cout << s << std::endl;  
           etr2.insert(s);
        }
    }
    
    std::cout << std::endl;
    
    for (const std::string& s : etr2) {
        std::cout << s << std::endl;    
    }
    
    /* Extract words start with letter 'H' & 
       second letter as 'A', and any other letter as 'A'
       but not second letter */
    // << I'm not sure  >>    
      
    return 0;
}

Link for running this program

Solution which I expected:

    for (const std::string& s : etr2) {
        size_t occ = s.find('A');
         // Repeat till end is reached
         while(occ != std::string::npos) {
            if (std::find(pos.begin(), pos.end(), occ) == pos.end()) {
                etr.insert(s);
             }
            // Get the next occurrence from the current position
            occ = s.find('A', occ + 1);
        }
    }

Find the link for this solution

Rose
  • 11
  • 6
  • `find_if` is your fried here I think. – lorro Aug 04 '22 at 17:28
  • 1
    For the "extract" part you could use [`std::copy_if`](https://en.cppreference.com/w/cpp/algorithm/copy) with a suitable [lambda](https://en.cppreference.com/w/cpp/language/lambda). And plain string [`find`](https://en.cppreference.com/w/cpp/string/basic_string/find) call to see if the letter `'A'` is anywhere else in the string. – Some programmer dude Aug 04 '22 at 17:30
  • /^HA/, /^H[^A]/, /^H[^A].*A/ here are 3 regexes, which allow you to do the above with a single function and passing a regex as a parameter. https://en.cppreference.com/w/cpp/regex – QuentinUK Aug 04 '22 at 17:36
  • @asimes I modified my explanation to be precise to along with the example. – Rose Aug 04 '22 at 17:38
  • @Rose, I deleted my comment after I saw you edited your question to avoid confusing new people – asimes Aug 04 '22 at 17:38
  • @Someprogrammerdude I was able to achieve with find. Thank you for giving me a clue!! – Rose Aug 04 '22 at 20:50

1 Answers1

0

The same way you checked other words: iterate over the set, but this time iterate over each word and check whether there is any A in suitable position.

But note that previous checks could be done much more efficiently with std::set as it is sorted, and you need to extract strings between "H" and "I" (I follows H). Two set::lower_bound calls would return you the range.

numzero
  • 2,009
  • 6
  • 6
  • You can also use `std::equal_range` to get the range, possibly even a bit more efficiently than two calls to `std::lower_bound` (though you do have to be a bit careful with your comparator to make it work). – Jerry Coffin Aug 04 '22 at 17:46
  • Ugh... for `equal_range` to work this way, one needs a `multiset` with a custom comparator IIUC. Sounds a bit too advanced for the task. – numzero Aug 04 '22 at 17:51
  • It can still use an `std::set`, but you do have to pass a comparator that looks only at the correct letter. – Jerry Coffin Aug 04 '22 at 17:52
  • To my understanding, `std::set::equal_range` can only return range of one element at most. As e.g. with a comparator looking at 0th character only, `std::set` can’t contain both `HELLO` and `HI` at same time; among equal strings, only first (or last?) inserted one will be there. – numzero Aug 04 '22 at 18:18
  • You can pass a comparator to `std::equal_range` itself, so it doesn't necessarily use the same comparison function as the underlying set. So, the underlying set can be sorted on the whole string, while equal_range looks only at the first character, the first two characters, and so on (which is pretty much what he wants for the case at hand). – Jerry Coffin Aug 04 '22 at 18:37
  • “You can pass a comparator”—according to [cppreference](https://en.cppreference.com/w/cpp/container/set/equal_range), you can’t. What you can do is pass a special key type, if the set was instantiated with a transparent comparator. I’d not test STL robustness in this aspect (what if it would only compare *second* char? Such order would be incompatible with the set’s own order. cppreference is silent on that, and I don’t want to open the standard now). – numzero Aug 04 '22 at 18:58