Find in vector

I need to find a substring.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

using namespace std;

int main() {
	int n;
	vector<string> words;
	string substring, word;
	cout << "Input the number of words: " << endl;
	cin >> n;
	cout << "write a substring" << endl;
	cin >> substring;
	cout << "Write the words: " << endl;
	//for (std::string word; std::cin >> word)
	for (int i = 0; i < n; i++) {
		cin >> word;
		words.push_back(word);
	}
	int it;
	it=find(words.begin(), words.end(),substring);

}

What you need is an iterator to string not int value.

replace you last 2 lines with this:


1
2
3
4
5
6
7
8
9
	auto it = std::find_if(words.begin(), words.end(), [&](const std::string& ref)
	{
		return static_cast<bool>(!std::strcmp(ref.c_str(), substring.c_str()));
	});

	if (it != words.end())
		std::cout << "string found: " << (*it).c_str();
	else
		std::cout << "nothing found" << std::endl;


additional headers needed:
 
#include <cstring> // std::strcmp  


EDIT:

I forgot, but I think this can be written in more simple way (without cstring header):
1
2
3
4
5
	
auto it = std::find_if(words.begin(), words.end(), [&](const std::string& ref)	
{
	return ref == substring;
});

Last edited on
@malibor: Your second example seeks whole words.

The objective is to seek from a vector such an element (word) that contains a substring. To seek substring from each word (up to first match).

To find a substring from string: http://www.cplusplus.com/reference/string/string/find/

1
2
3
4
auto it = std::find_if( words.begin(), words.end(), [&](const std::string& ref)	
  {
    return std::string::npos != ref.find( substring );
  });



There are regular expressions too, that allow fancier "finds".
Last edited on
@keskiverto
yes, you are correct about this, I already thought to give such example but problem is that multiple strings in a vector may have same substring, and how are you going to handle that case? what to return to caller?

If OP really needs that functionality then neither of our examples will work, instead additional function may be needed that returns ie. new vector of strings that contains all the strings which contain a substring.

EDIT:
here is updated version that fill vector with strings that contain a substring:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        // note: taking address not copies!
        // pointers may become invalid if original vector relocates internally
	std::vector<const std::string*> finds = {};

	std::for_each(words.begin(), words.end(), [&](const std::string& ref)
		{
			if (std::string::npos != ref.find(substring))
				finds.push_back(&ref);
		});

	if (!finds.empty())
		for (const auto& ref : finds)
			std::cout << *ref << std::endl;
        else std::cout << "nothing found";

Last edited on
Great, it's run, but I didn't understand any parts.

Why you used {}?
 
vector<const string*> finds = {};


What a function of?
 
for (const auto& ref : finds)
victorio wrote:
I need to find a substring.

@malibor:
A word was requested, and that is what find_if() returns: first "valid" word (or none).

"All words that contain substring" is different goal.


T x = {}; declares variable named 'x' that has type 'T' and initializes it with empty value.
C++11 allows also syntax: T x {};

However, the std::vector is a class that has default constructor. The initializer is unnecessary.


1
2
3
for ( const auto& ref : finds ) {
  std::cout << *ref << std::endl;
}

This is ranged for-syntax that was added by C++11.
1
2
3
4
5
6
7
8
9
10
11
vector<string> words;
// ranged for
for ( string w : words ) {
  std::cout << w << std::endl;
}

// old for
for ( size_t x=0; x < words.size(); ++x ) {
  string w = words[x];
  std::cout << w << std::endl;
}


The auto keyword in C++11 (and later) makes the compiler deduce typename. The 'finds' has type std::vector<const std::string*> and thus 'auto' in the loop (probably) means const std::string*

Note: Constant reference to a pointer yields no advantage in this case.
I understand now, thank you!
@keskiverto
apologies, even now, I'm not sure what the real intention of OP was.

@victorio
vector<const string*> finds = {};
keskiverto explain it all, but I have this habit mainly because of analyzer warnings from:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md
Always initialize variables, use initialization lists for member variables.

and it's not even correct. it should be:
vector<const string*> finds{};
which is just being explicit, and good practice.
Topic archived. No new replies allowed.