I have two strings, i.e: APPLE and APPLEA. I want to iterate over APPLE and check if its characters belong to APPLEA. I have done this:
int counter=0;
for (j=0;j<dictionary[i].size();j++)
{
if (word_to_match.find(dictionary[i][j]) != std::string::npos)
{
counter++;
}
}
Where dictionary is just a std::vector that has APPLE and other words.
Is it possible to avoid the for loop by using std::transform or another tool?
----------------------------------EDIT------------------------------------
I have this, I dont know if it could be even cleaner
std::for_each(dictionary[i].begin(),dictionary[i].end(),[&word_to_match,&counter](char const &c){
if (word_to_match.find(c) != std::string::npos)
{
counter++;
}
});
How about std::count_if
int count = std::count_if(dictionary.begin(), dictionary.end(), [&](const std::string& s){
return word_to_match.find(s) != std::string::npos;
});
assuming dictionary is a container for std::string, eg. std::vector<std::string>. You can modify it accordingly to match your case.
Related
I have been trying to remove the value False and 0;0 from a vector<string> plan; containing the following
1003;2021-03-09;False;0;0;1678721F
1005;2021-03-05;False;0;0;1592221D
1005;2021-03-06;False;0;0;1592221D
1003;2021-03-07;False;0;0;1592221D
1003;2021-03-08;False;0;0;1592221D
1004;2021-03-09;False;0;0;1592221D
1004;2021-03-10;False;0;0;1592221D
1001;2021-03-11;False;0;0;1592221D
but the solutions I have found only work with int, and I tried the following
remove(plan.begin(), plan.end(), "False");
also with erase, but it didn't work
what is the mistake that I am making, or how should I do to eliminate the values that I want, which are in the position [2] [3] and [4], thanks for any help.
[Note: With the assumption 1003;2021-03-09;False;0;0;1678721F corresponding to a row inside std::vector<string>]
std::remove : Removes from the vector either a single element (position) or a range of elements ([first, last)).
In case std::vector<string> plan contains value False then it is removed.
std::vector < std::string > plan =
{
"1003","2021-03-09","False","0;0","1678721F"
};
std::remove(plan.begin(),plan.end(),"False");
In your case you need to remove given sub-string from each row of the plan. You need to iterate through all the rows to remove given value using std::string::erase.
std::vector < std::string > plan =
{
"1003;2021-03-09;False;0;0;1678721F",
"1005;2021-03-05;False;0;0;1592221D",
"1005;2021-03-06;False;0;0;1592221D",
"1003;2021-03-07;False;0;0;1592221D",
"1003;2021-03-08;False;0;0;1592221D",
"1004;2021-03-09;False;0;0;1592221D",
"1004;2021-03-10;False;0;0;1592221D",
"1001;2021-03-11;False;0;0;1592221D"};
for (auto & e:plan)
{
//As position of False;0;0; is at a fixed index, i.e: from index:16, 10 characters are removed
e.erase (16, 10);
}
To generalize, You can make use of std::String::find to find a sub-string and erase it.
void removeSubstrs(string& s, string p) {
string::size_type n = p.length();
for (string::size_type i = s.find(p);
i != string::npos;
i = s.find(p))
s.erase(i, n);
}
int
main ()
{
std::vector < std::string > plan =
{
"1003;2021-03-09;False;0;0;1678721F",
"1005;2021-03-05;False;0;0;1592221D",
"1005;2021-03-06;False;0;0;1592221D",
"1003;2021-03-07;False;0;0;1592221D",
"1003;2021-03-08;False;0;0;1592221D",
"1004;2021-03-09;False;0;0;1592221D",
"1004;2021-03-10;False;0;0;1592221D",
"1001;2021-03-11;False;0;0;1592221D"};
for (auto & e:plan)
{
removeSubstrs (e, ";False;0;0");
}
for (auto e:plan)
std::cout << e << std::endl;
return 0;
}
[Note: This answer assumes that each line corresponds to an element in the vector]
With the statement
remove(plan.begin(), plan.end(), "False");
you try to remove all elements from the vector that are equal to "False".
You need to iterate over the vector and erase the sub-string from each and every string in the vector.
For example you can use a range for loop to iterate over all the strings (or rather references to them), and then use the std::string functions find to find the sub-strings you want to remove and replace to replace the sub-strings with empty strings (i.e. nothing).
If you are sure that there is only one occurrence of "First" and "0;0" in your vector, you can use something like this:
std::string EraseFirstSubString(
const std::string & main_str,
const std::string & sub_str)
{
std::string new_main_str = main_str;
size_t pos = new_main_str.find(sub_str);
if (pos != std::string::npos)
{
new_main_str.erase(pos, sub_str.length());
}
return new_main_str;
}
int main()
{
std::vector<std::string> plan = {
"1003;2021-03-09;False;0;0;1678721F",
"1005;2021-03-05;False;0;0;1592221D",
"1005;2021-03-06;False;0;0;1592221D",
"1003;2021-03-07;False;0;0;1592221D",
"1003;2021-03-08;False;0;0;1592221D",
"1004;2021-03-09;False;0;0;1592221D",
"1004;2021-03-10;False;0;0;1592221D",
"1001;2021-03-11;False;0;0;1592221D"
};
for (std::string & str : plan)
{
str = EraseFirstSubString(str, "False");
str = EraseFirstSubString(str, "0;0");
}
};
But, if you think that you may have many occurrences of those sub-strings, you should improve a little bit your sub-string removing mechanism like this:
std::string EaraseSubStrings(
const std::string & main_str,
const std::string & sub_str)
{
std::string new_main_str = main_str;
size_t pos = new_main_str.find(sub_str);
while (pos != std::string::npos)
{
new_main_str.erase(pos, sub_str.length());
pos = new_main_str.find(sub_str);
}
return new_main_str;
}
If you already have a vector of individual std::string objects, you can easily use the operations that the strings library offers.
#include <algorithm>
#include <vector>
#include <string>
// before C++20 change constexpr to inline
constexpr void change(std::vector<std::string>& sv, std::string const& rem) {
for_each(beign(sv),end(sv), [&rem](std::string& s) {
s.erase(std::min(s.size(),s.find(rem)), rem.size());
});
}
I have a vector of strings with different chars infront of them. for example:
"Hello
(Hello
I want to remove the first occurrence of the char. So if there is a " or ( before the word, I want it gone. My code so far is this.
void wash(std::vector<std::string> & data)
{
std::string b_chars = "\"'("; //Before_chars
std::string a_chars = "!?;,:.\"')"; //after_chars
data.erase(std::remove_if(data.begin(), data.end(), [&b_chars](const char& c) {
return data.find_first_of(b_chars) != std::string::npos;
}), data.end());
}
Your condition is wrong - you should determine whether c is one of the offending characters, which is b_chars.find(c) != std::string::npos.
To iterate over the entire vector, you could go:
std::for_each(data.begin(),
data.end(),
[&b_chars](std::string& str)
{
str.erase(std::remove_if(str.begin(),
str.end(),
[&b_chars](const char& c)
{return b_chars.find(c) != std::string::npos;}),
data.end());
});
}
But it makes sense to have a separate string-washing function and not limit yourself to vectors of strings (I didn't read your code properly because this is a more useful building block to start with):
void wash_string(std::string & s)
{
static const std::string b_chars = "\"'("; //Before_chars
static const std::string a_chars = "!?;,:.\"')"; //after_chars
s.erase(std::remove_if(s.begin(),
s.end(),
[&b_chars](const char& c)
{return b_chars.find(c) != std::string::npos;}),
s.end());
}
void wash(std::vector<std::string> & data)
{
std::for_each(data.begin(), data.end(), wash_string);
}
There are various problems with your code:
in you code you dont remove chars from a string but from a vector of string. You should iterate your vector and do the removal on each string.
As in molbdnilo answer, you need to change the condition of your lambda to find character inside the string of offending chars
void wash(std::vector<std::string> & data)
{
std::string b_chars = "\"'("; //Before_chars
std::string a_chars = "!?;,:.\"')"; //after_chars
for (auto& str : data) {
str.erase(std::remove_if(str.begin(), str.end(),
[&](const char &c) { return b_chars.find_first_of(c) != std::string::npos; }),
str.end());
}
}
If you want to remove these the chars only before the first occurrence of a 'normal char':
for (vector<std::string>::iterator vt_it = data.begin(); vt_it<data.end(); ++vt_it)
{
std::string::iterator str_it = (*vt_it).begin();
while (str_it != (*vt_it).end())
{
if ((b_chars).find((*str_it)) == std::string::npos)
break;
str_it++;
}
(*vt_it).erase ((*vt_it).begin(), str_it);
}
But if you want to remove all those chars:
for (vector<std::string>::iterator vt_it = data.begin(); vt_it<data.end(); ++vt_it)
{
(*vt_it).erase(
std::remove_if(
(*vt_it).begin(),
(*vt_it).end(),
[&b_chars](const char& c) {return b_chars.find(c) != std::string::npos;}),
(*vt_it).end()
);
}
OBS. You didn't reffer anything about what you want to do with a_chars. I tested all the codes in these post, included mine.
So I have a couple methods defined, one checks if the next is a word, one checks if there is a next word.
I take inputs for the text files, add the files content to a vector, then use the for loop
I can make it work by simply doing a for loop through the vector:
for (int x = 0; x != v2.size(); ++x) {
But I want to use my two methods
bool ReadWords::isNextWord()
and
string ReadWords::getNextWord()
{
//take the input of the file until end of list is reached and return it
}
So how would I do something like
vector<string> bigTextFile;
vector<string> vct;
while(vct.isNextWord) {
vct.getNextWord
if(vct.getNextWord == bigTextFile[i] {
counter++
}
}
Let me know if you need any more of the code
What about this:
vector<string> bigTextFile;
vector<string> vct;
while(ReadWords::isNextWord(vct))
{
string nextWord = ReadWords::getNextWord(vct);
if(nextWord == bigTextFile[i])
{
counter++;
}
}
You could make your functions take in a vector as a parameter then do the work on the vector inside each function. I'm not 100% sure what your implementation is since its not the complete code.
I'm not sure why are you trying to write an object, but here is how I would have approached the problem:
Step 1. Create a predicate for the words
bool is_needed_word(const std::string& word, const std::vector<std::string>& needed_words)
{
if (std::find(needed_words.begin(),
needed_words.end(),
word) != needed_words.end())
return true;
}
//some where in your function
std::vector<std::string> needed_words{"apple", "moon", "etc"};
auto predicate = [&needed_words](const auto& word)
{return is_needed_word(word, needed_words);}
Step 2. Copy/count/whatever you want to do with the words in the stream
//copying
std::vector<std::string> extracted_words;
std::ifstream input_file{"input.txt"};
//check if opened correctly
std::copy_if(std::istream_iterator<std::string>(input_file), {},
std::back_inserter(extracted_words));
//counting
std::size_t occurrence_counter = std::count_if(std::istream_iterator<std::string>(input_file),{},predicate)
It's in the form of a word so let's say I'm given the string "foo", and inside my array there are words like "food", "fool", "foo". All three of them should be printed out.
I haven't made a solid attempt at it yet cause I don't know how to wrap my head around it. Any idea?
Assuming you're using std::string, you could use string::find to see if one string is contained in another.
If you have a vector of strings, you might use that along with (for example) std::remove_copy_if to print out all the words from the vector that contain the chosen word:
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <iostream>
int main() {
std::vector<std::string> words{"food", "fool", "foo", "tofoo", "lood", "flood"};
std::string word = "foo";
std::remove_copy_if(words.begin(), words.end(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[&](std::string const &s) {
return s.find(word) == std::string::npos;
});
}
Result:
food
fool
foo
tofoo
You could do something simple, like iterating through each character in the string and checking it against the characters in the string you are trying to match using a separate function. If three characters in a row match the string you are searching for, add it to a vector or something and display them.
// Variables
bool charMatched = false;
vector<string> *stringVec = new vector<string>();
int index = 0;
int counter = 0;
string str = "Whatever you are trying to match";
for (char &c : strings[index]) // For each character in string
{
// Check for match
if (checkChar(c))
{
counter++;
charMatched = true;
if(counter == str.length())
stringVec->push_back(strings[index]);
}
else
{
index++;
counter = 0;
break;
}
}
bool checkChar(char c)
{
// Iterator to go through match string
static string::iterator it = str.begin();
if (c == *it)
{
if (it == str.end())
it = str.begin(); // Reset iterator
else
it++; // Increment iterator
return true;
}
else
{
if (it == str.end())
it = str.begin(); // Reset iterator
else
it++; // Increment iterator
return false;
}
}
You will have to tweak it a little to work with an array the way you want it to but something like this should do what you want. I did not run this through a compiler, I wrote it in Notepad so there may be small syntax errors. I hope this helps!
I have a string, like e.g. acaddef or bbaaddgg. I have to remove from it, as fast as possible, all repeating characters. So, for example, pooaatat after should look like poat and ggaatpop should look like gatpo. Is there any built-in function or algorithm to do that quickly? I tried to search STL, but without satisfaing result.
Okay, so here are 4 different solutions.
Fixed Array
std::string str = "pooaatat";
// Prints "poat"
short count[256] = {0};
std::copy_if(str.begin(), str.end(), std::ostream_iterator<char>(std::cout),
[&](unsigned char c) { return count[c]++ == 0; });
Count Algorithm + Iterator
std::string str = "pooaatat";
// Prints "poat"
std::string::iterator iter = str.begin();
std::copy_if(str.begin(), str.end(), std::ostream_iterator<char>(std::cout),
[&](char c) { return !std::count(str.begin(), iter++, c); });
Unordered Set
std::string str = "pooaatat";
// Prints "poat"
std::unordered_set<char> container;
std::copy_if(str.begin(), str.end(), std::ostream_iterator<char>(std::cout),
[&](char c) { return container.insert(c).second; });
Unordered Map
std::string str = "pooaatat";
// Prints "poat"
std::unordered_map<char, int> container;
std::copy_if(str.begin(), str.end(), std::ostream_iterator<char>(std::cout),
[&](char c) { return container[c]++ == 0; });
AFAIK, there is no built-in algorithm for doing this. The std::unique algorithm is valid if you want to remove only consecutive duplicate characters.
However you can follow the following simple approach:
If the string contains only ASCII characters, you can form a boolean array A[256] denoting whether the respective character has been encountered already or not.
Then simply traverse the input string and copy the character to output if A[character] is still 0 (and make A[character] = 1).
In case the string contains arbitrary characters, then you can use a std::unordered_map or a std::map of char to int.
Built-in regular expressions should be efficient, i.e.
#include <regex>
[...]
const std::regex pattern("([\\w ])(?!\\1)");
string s = "ssha3akjssss42jj 234444 203488842882387 heeelloooo";
std::string result;
for (std::sregex_iterator i(s.begin(), s.end(), pattern), end; i != end; ++i)
result.append((*i)[1]);
std::cout << result << std::endl;
Of course, you can modify the cpaturing group to your needs.
The good thing is that it is supported in Visual Studio 2010 tr1 already. gcc 4.8, however, seems to have a problem with regex iterators.