Reputation: 31
I am currently writing a program that is composed of a string vector full of words that have a certain letter all in the same position.
For example my vector might look like this:
vector<string> v = { "CRYPT", "CYSTS", "WRYLY", "TRYST" };
The idea is a letter is guessed i.e "Y" in this case and the program chooses the first string in the vector, goes through the string vector and keeps in the words that have the Y in the same position as the first word in the vector. In this case, the program would choose "CRYPT". Now, I need the program to go through the string vector and remove any words that have duplicates of that letter in some additional position as compared to the first word "CRYPT" while keeping in words that have the "Y" in the same exact position with no other "Y"s in other places than the first words place. So I need the output of the vector to look something like this after removing any additional duplicates and keeping the other words that have the letter in the same position.
vector<string> v = { "CRYPT", "TRYST" };
I was thinking about looping through the vector and looping through each string to go through each char and check however I cannot remove the element from the vector while looping through it or it will cause issues. Maybe using remove_if for vectors but unsure of how to write the predicate. Any help is appreciated! Thanks!
Upvotes: 0
Views: 265
Reputation: 39
Let's start with your vector, following by guessed character and your "main" string
vector<string> v = { "CRYPT", "CYSTS", "WRYLY", "TRYST" };
string mainStr = v[0];
char guessed = 'Y';
As you said, we need to iterate over all strings and remove them, if they don't follow our rules. So just do it, but we will not iterate with "for_each", we'll use simple loop
for (size_t i = 1; i < v.size(); ++i) {
for (size_t j = 0; j < v[i].size(); ++j) {
if (v[i][j] == guessed && (j >= mainStr.size() || mainStr[j] != guessed)
|| j < mainStr.size() && mainStr[j] == guessed && v[i][j] != guessed) {
v.erase(find(v.begin(), v.end(), v[i]));
--i;
break;
}
}
}
In the inner loop, as you can see, when we removing such a string that we don't want to see in the collection, we just step back with our "iterator", so we don't break any vector conditions and we can continue iterate over strings.
In the end you can simply see, that we've done right
for (auto& str : v) {
cout << str << '\n';
}
Upvotes: 0
Reputation: 44274
One approach is to define a functor that evaluates whether a given string matches the criteria for getting copied to a result vector. The functor is then used with copy_if
.
Something like:
#include <iostream>
#include <vector>
#include <algorithm>
struct do_copy
{
do_copy(char m) : match(m) {}
char match;
size_t pos;
bool found {false};
bool operator()(const std::string& s)
{
if (found)
{
return s.size() > pos &&
s[pos] == match &&
std::count(s.begin(), s.end(), match) == 1;
}
for (int p = 0; p < s.size(); ++p)
{
if (s[p] == match)
{
pos = p;
found = true;
return true;
}
}
return false;
}
};
int main() {
std::vector<std::string> v = { "CRYPT", "CYSTS", "WRYLY", "TRYST" };
std::vector<std::string> r;
char guess = 'Y';
std::copy_if(v.begin(),
v.end(),
std::back_inserter(r),
do_copy(guess));
// Print the result
std::cout << r.size() << " elements found:" << std::endl;
for (auto& s : r)
{
std::cout << s << std::endl;
}
return 0;
}
Output:
2 elements found:
CRYPT
TRYST
Upvotes: 1