c++ find duplicate strings in vector and print all occurrence of them

So i'm looking for a soultion to print duplicate strings in a vector. If the vector contains {a,b,c,a,d,a,a} i want to print each "a" out of the vector. For the code i'm using i get only 1 "a " out of 2.

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
28
29
30
31
  #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
string wordAppend(vector<string>strings)
{
	string s;
	vector <string>temp;
	sort(strings.begin(), strings.end());
	for (int i = 1; i < strings.size(); i++)
	{
		if (strings[i - 1] == strings[i])
		{
			temp.push_back(strings[i]);
		}
	}
	for (int i = 0; i < temp.size(); i++)
	{
		cout << temp[i];
	}

	
	return s;
}

int main()
{
	vector <string> strings {"a","b","c","a"};
	wordAppend(strings);
}
Last edited on
Here is an example I had in one of my projects, should help you out:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string stringToSearch = "This is a string of text to search.";
string stringToFind{};

cout << stringToSearch << endl;

cout << "Enter a string to find" << endl;

getline(cin, stringToFind);

int wordAppearance{};

for (int position = stringToSearch.find(stringToFind, 0); position != string::npos; position = stringToSearch.find(stringToFind, position))
{
       cout << "Found " << ++wordAppearance << " instances of " << stringToFind << " at 
       position " << position << endl;
       position++;
}
Last edited on
You are only pushing the duplicate strings to the vector - which doesn't include the first one found. So for a b c a you show a and for a b c a d a a you show aaa.

Why do you want to show the duplicate occurrences?

As an alternative, depending upon what you are trying to achieve, consider using a map to store the number of occurrences of a string and then deal with those strings that have an occurrence > 1.

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
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <string_view>
using namespace std;

void wordAppend1(const vector<string>& strings)
{
	map<string_view, size_t> temp;

	for (const auto& s : strings)
		++temp[s];

	for (const auto& [str, cnt] : temp)
		if (cnt > 1)
			for (size_t i = 0; i < cnt; ++i)
				cout << str << ' ';
}

int main()
{
	const vector<string> strings {"a","b","c","a","d","a","a"};

	wordAppend1(strings);
}



a a a a

Last edited on
Sorry for presenting only bits. This is the whole problem.

Loop over the given array of strings to build a result string like this: when a string appears the 2nd, 4th, 6th, etc. time in the array, append the string to the result. Return the empty string if no string appears a 2nd time.

it should be done using vector <string>. And i tough about using map but never really used them.

Last edited on
First of all, WordAppend() should not print the result. It should just return the resulting string and then main() should print it:
1
2
3
4
5
int main()
{
	const vector<string> strings {"a","b","c","a","d","a","a"};
	cout << wordAppend1(strings);
}


To store only the 2nd, 4th, 6th, etc appearances of the string, you could count the appearance number in your loop and append the duplicate if it's even. One caution though, be sure to reset your counter when you see a string that isn't a duplicate.
I don't understand this two parts marked with * :
map<*string_view*, size_t> temp , for (const auto& *[str, cnt]* : temp) .
Last edited on
Hello DumbGuy,

"string_view" is from the C++ 2017 standards and I know that you know all about them right?


Loop over the given array of strings to build a result string like this:


Where does this say to create a 2nd vector? You do create string s;, needs a better name, but never use it properly.

As dhayden pointed out the function should only be checking for duplicates and if so create a string of those duplicates.

If you set up the function correctly when you return "result", what you call "s", it will either be empty or have something in it.

Back in "main" you can determine the size of the string and decide what you need to print out.

With what I have changed this is the output I get:

 The duplicate strings are:
 a a a c


 Press Enter to continue:

Or

     There are no duplicates.


 Press Enter to continue:



Here is a little trick that helps with debugging and testing:
1
2
3
vector <string> strings
//{ "a", "b", "c", "a", "c", "a", "a" };
{ "a", "b", "d", "e", "f", "g", "h" };

For lines 2 and 3 make as many as you want and just the comment(s) as needed. Much faster for testing.

You do not need a map or to count anything. You already have what you need. It just needs to be used differently.

Andy
you can do it faster ways (sorting goes through the data more than once), but the easy solution is to sort the input array (or a copy of it if you need it again later) and iterate it. then you have a,a,a,a,b,b,b,b,c,c,c, .... and you can be assured that when you hit b there are no more a's after it, and so on. you just count or print or whatever. Unless your arrays are exceedingly large (many millions) it would still do it in < 1 second.

so i made it. Is it good? "umm no". Does it work? "i think so".
Didn't you overcomplicate? "yes". Should it ever be used "Oh god no".
I'm happy if someone can post something not overcomplicated just so i can learn from it.
Thanks for all the help!
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <string_view>
#include <algorithm>
using namespace std;
string wordAppend(const vector<string>&strings)
{
	map<string, int> temp;
	int count = 0;
	string s;
	for (auto const& s: strings)
	{
		++temp[s];
	}
	for (auto const& i : temp)
	{
		for (int h = 0; h < i.second; h++)
		if (i.second > 1)
		{
			count++;
		}
	}
	for (auto const& i : temp)
	{
		for (int h = 0; h < i.second; h++)
		{
			if (i.second > 1)
			{
				if (count / 2 == 1 and count % 2 == 0)
				{
					s = i.first;
				}
				else if ((count > 2) and (count % 2 == 0))
				{
					s = i.first;
					s.append(s);
				}
			}
		}
	}
	return s;
}

int main()
{
	const vector <string> strings {"a","b","c","b","b"};
	cout << wordAppend(strings)<< " ";
}
Last edited on
Hello DumbGuy,

This is what I came up with. And from what you said I believe it follows what you said:
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

string wordAppend(vector<string> strings)
{
    string result;
 
    sort(strings.begin(), strings.end());

    for (int i = 1; i < strings.size(); i++)
    {
        if (strings[i - 1] == strings[i])
        {
            result += strings[i] + ' ';
        }
    }

    return result;
}

int main()
{
    std::string result;
    vector <string> strings
        { "a", "b", "c", "a", "c", "a", "a" };
    //{ "a", "b", "d", "e", "f", "g", "h" };

    result = wordAppend(strings);

    if (result.size())
    {
        std::cout << "\n The duplicate strings are:\n " << result << '\n';
    }
    else
    {
        std::cerr << "\n     There are no duplicates.\n";
    }

    // A fair C++ replacement for "system("pause")". Or a way to pause the program.
    // The next line may not be needed. If you have to press enter to see the prompt it is not needed.
    //std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');  // <--- Requires header file <limits>.
    std::cout << "\n\n Press Enter to continue: ";
    std::cin.get();

    return 0;  // <--- Not required, but makes a good break point.
}


Andy
Is this what you are after (C++17)? If not, can you provide a sample required output from the input:

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 <iostream>
#include <string>
#include <vector>
#include <map>
#include <string_view>
using namespace std;

string wordAppend(const vector<string>& strings)
{
	map<string_view, int> temp;
	string dup;

	for (auto const& s : strings)
		++temp[s];

	for (const auto& [str, cnt] : temp)
		if (cnt % 2 == 0)
			for (size_t n = 0; n < cnt / 2; ++n, dup += str);

	return dup;
}

int main()
{
	const vector <string> strings {"a","b","c","b","b", "b", "c"};
	cout << wordAppend(strings) << " ";
}



bbc

Last edited on
Hello DumbGuy,

I was playing with the program and came up with this output by changing line 18.

[0]  This is a dup
[1]  This is a dup
[2]  This is a dup
[3]  This is a string
[4]  This is string 2
[5]  This is string 3
[6]  This is string 4


 The duplicate strings are:
 [1] This is a dup
 [2] This is a dup



 Press Enter to continue:


The for loop for the first part was mostly for checking the sort. Not something I planed to leave.

Andy
Based on this statement:
Loop over the given array of strings to build a result string like this: when a string appears the 2nd, 4th, 6th, etc. time in the array, append the string to the result. Return the empty string if no string appears a 2nd time.


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 <iostream>
#include <string>
#include <vector>
#include <set>
using namespace std;

string everySecondOccurrence( const vector<string> &V )
{
   string result;
   set<string> oddCounts;
   for ( string s : V )
   {
      auto pr = oddCounts.insert( s );
      if ( !pr.second )
      {
         result += s;
         oddCounts.erase( pr.first );
      }
   }
   return result;
}

int main()
{
   vector<string> test = { "a", "b", "c", "a", "d", "a", "a", "a", "d" };
   cout << everySecondOccurrence( test ) << '\n';
}


aad
Last edited on
Topic archived. No new replies allowed.