How to count duplicates in a vector (C++) - c++

I was working through an exercise in C++ Primer. Actually, I refined my first version. Problem is I not only want to detect duplications in a vector, but also how many times they were duplicated. I'm having trouble with the latter.
Here is my code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> nums{1,3,1,5,7,8,9,7};
sort(nums.begin(), nums.end());
for(unsigned int i = 0; i != nums.size(); ++i){
if(nums[i] == nums[i + 1]){
cout << nums[i] << " is a duplicated number" << endl;
}
}
return 0;
}
EDIT: Also just noticed my logic is flawed. If a number appears more than twice it will print out multiple times it's a duplicate. Which is redundant.

Use a std::map
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
using namespace std;
int main()
{
map<int, int> duplicate;
vector<int> nums{1,3,1,5,7,8,9,7,1};
vector<int> nums_sorted{nums};
sort(begin(nums_sorted), end(nums_sorted));
auto beg = begin(nums_sorted) + 1;
for (;beg != end(nums_sorted); ++beg) {
if (*beg == *(beg - 1)) {
duplicate[*beg]++;
}
}
for (const auto& i : duplicate)
cout << i.first << " appear " << i.second+1 << " times" << '\n';
}
Outputs:
1 appear 3 times
7 appear 2 times

You can pair up std::unique<>() with std::distance<>():
std::sort(nums.begin(), nums.end());
auto unique_end = std::unique(nums.begin(), nums.end());
std::cout << std::distance(nums.begin(), unique_end);

You were almost there, here is my suggested solution:
live
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> nums{1,3,1,5,7,8,9,7};
sort(nums.begin(), nums.end());
for(auto it = std::cbegin(nums); it != std::cend(nums); ) {
int dups = std::count(it, std::cend(nums), *it);
if ( dups > 1 )
cout << *it << " is a duplicated number, times: " << dups << endl;
for(auto last = *it;*++it == last;);
}
return 0;
}

A stupid but quick solution:
#include <map>
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> nums{1,3,1,5,7,8,9,7,1};
std::map<int, int> dups;
for(int i : nums)
++dups[i];
for(auto& dup : dups)
cout << "Number " << dup.first << " has " << dup.second - 1 << " duplicates\n";
}

Related

c++ how to print how many times each integer appears in the STL list

using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
}
return 0;
}
I wanted to use std::count() but I am not able to do it right. I tried to do the following:
using namespace std;
int main()
{
list<int> numbers; list<int> numb;
for (int i = 0; i<10; i++)
numbers.push_back(rand() % 20);
list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
cout << *it << " ";
while (it != numbers.begin() && it != numbers.end())
{
++it;
*it = count(it, numbers.begin(), numbers.end());
cout << " " << *it;
}
cout << endl;
}
return 0;
}
But it gives me an error:
binary == no operator found which takes a left hand operator type 'int' (or there is not acceptable conversion).
I know I am doing something wrong.
I also tried a few more things, like int numb = std::count(numbers.begin()), numbers.end(), *it), but it didn't work either. So, I want to know if there is a special operator to count values in a list.
You need to look at the signature for std::count again. It takes three parameters std::count(InputIterator first, InputIterator last, const T& val); and it returns the number of occurrences of val in your data set. So something like this should work for you where theNumber is the number you're counting.
#include <algorithm>
int occurrences = std::count(numbers.begin(), numbers.end(), theNumber);
You are not using iterators correctly (you are modifying it while you are still using it to iterate the list), and you are not calling std::count() correctly.
The code should look more like this instead:
#include <iostream>
#include <list>
#include <algorithm>
#include <cstdlib>
int main()
{
std::list<int> numbers;
int numb;
for (int i = 0; i < 10; i++)
numbers.push_back(std::rand() % 20);
std::list<int>::iterator it;
for (it = numbers.begin(); it != numbers.end(); ++it)
{
numb = std::count(numbers.begin(), numbers.end(), *it);
std::cout << *it << " " << numb << std::endl;
}
/* or:
for (int value : numbers)
{
numb = std::count(numbers.begin(), numbers.end(), value);
std::cout << value << " " << numb << std::endl;
}
*/
return 0;
}
But, like others said, you should use a std::map to track the counts, so you can account for duplicates, eg:
#include <iostream>
#include <list>
#include <map>
#include <cstdlib>
int main()
{
std::list<int> numbers;
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numbers.push_back(rand() % 20);
for (std::list<int>::iterator it = numbers.begin(); it != numbers.end(); ++it)
numb[*it]++;
/* or:
for (int value : numbers)
numb[value]++;
*/
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
Which can be reduced to this:
#include <iostream>
#include <map>
#include <cstdlib>
int main()
{
std::map<int, int> numb;
for (int i = 0; i < 10; i++)
numb[rand() % 20]++;
for (std::map<int, int>::iterator it = numb.begin(); it != numb.end(); ++it)
std::cout << it->first << " " << it->second << std::endl;
/* or:
for (auto &item : numb)
std::cout << item.first << " " << item.second << std::endl;
*/
return 0;
}
In general, using a map is a better approach to your problem, but if you have to solve it using lists here is one possible solution:
#include <iostream>
#include <algorithm>
#include <list>
int main()
{
std::list<int> numbers, unique_num, numb;
int num;
// Create both the original list and a list that
// will be left with only unique numbers
for (int i = 0; i<10; i++){
num = rand() % 20;
numbers.push_back(num);
unique_num.push_back(num);
}
// Sort and select the unique numbers
unique_num.sort();
unique_num.unique();
// Count unique numbers and store the count in numb
std::list<int>::iterator iter = unique_num.begin();
while (iter != unique_num.end())
numb.push_back(count(numbers.begin(), numbers.end(), *iter++));
// Print the results
for(std::list<int>::iterator iter1 = unique_num.begin(), iter2 = numb.begin();
iter2 != numb.end(); iter1++, iter2++)
std::cout<< "Number " << *iter1 << " appears " <<
*iter2 << ( *iter2 > 1 ? " times " : " time" ) << std::endl;
return 0;
}
The program uses another list, unique_num, to hold unique numbers occurring in numbers. That list is initially created identical to numbers and is then sorted and the duplicates are removed.
The program then iterates through numbers in that unique list and uses count to get the number of occurrences of each of them in the original numbers list. The number of occurrences is then stored in a new list, numb.
When printing, the program uses a ternary operator to check whether it should print "time" or "times" depending whether the result implies one or more than one occurrence.
Note - if you want different list values each time you run your program you need to change the random seed using srand. Include the header #include <time.h> in your program and the line srand(time(NULL)); at the beginning of your main.
I suggest you use a map:
map<int, int> counts;
for(int val : Numbers)
++counts[val];
WITH ADDITIONAL MEMORY:
You can use buckets, to get complexity O(N + MAX_NUM). So when MAX_NUM <= N we have O(N):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
const int MAX_NUM = 20;
const int N = 10;
int main() {
std::list<int> numbers;
int buckets[MAX_NUM];
std::fill(buckets, buckets + MAX_NUM, 0);
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (int i = 0; i < MAX_NUM; i++) {
if (buckets[i]) std::cout << "value " << i << " appears in the list " << buckets[i] << " times." <<std::endl;
}
return 0;
}
For big data i would recommend using std::unordered_map for buckets and then geting complexity O(N) (thanks to hashing):
#include <iostream>
#include <list>
#include <algorithm>
#include <ctime>
#include <unordered_map>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
std::unordered_map<int, int> buckets;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// computing
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
buckets[*it]++;
}
//printing answers
for (auto & k_v : buckets) {
std::cout << "value " << k_v.first << " appears in the list " << k_v.second << " times." <<std::endl;
}
return 0;
}
WITHOUT ADDITIONAL MEMORY:
In more universal way, you can use std::vector instead of std::list and std::sort on it, and then count value changes in a simple for. Complexity is O(N log N):
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::vector<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
std::sort(numbers.begin(), numbers.end());
//printing answers for sorted vector
if (numbers.size() > 0) {
int act_count = 1;
for (int i = 1; i < numbers.size(); i++) {
if (numbers[i] != numbers[i -1]) {
std::cout << "value " << numbers[i-1] << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
}
std::cout << "value " << numbers[numbers.size() - 1] << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}
You can also do the above on std::list, getting also O(nlogn), but can't use std::sort:
#include <iostream>
#include <list>
#include <ctime>
const int N = 10;
const int MAX_NUM = 20;
int main() {
std::list<int> numbers;
srand(time(NULL));
for (int i = 0; i < N; i++) numbers.push_back(rand() % MAX_NUM);
// sorting
numbers.sort();
//printing answers for sorted list
if (!numbers.empty()) {
int act_count = 0;
auto prev = numbers.begin();
for (auto it = numbers.begin(); it != numbers.end(); it++) {
if (*it != *prev) {
std::cout << "value " << *it << " appears in the list " << act_count << " times." <<std::endl;
act_count = 1;
} else {
act_count++;
}
prev = it;
}
std::cout << "value " << *prev << " appears in the list " << act_count << " times." <<std::endl;
}
return 0;
}

Increase all elements of a List in C++

#include <iostream>
#include <vector>
#include <iterator>
#include <iostream>
#include <cmath>
#include <string>
#include <utility>
#include <cstring>
#include <list>
using std::vector;
using std::cout;
using std::list;
using std::endl;
using std::string;
using namespace std;
template <typename T>
void showContents(T& input)
{
typename T::iterator it;
for (it=input.begin(); it != input.end(); it++)
{ cout << *it << " "; }
cout << endl;
}
int main()
{
int B[10] = {0,1,2,3,4,5,6,7,8,9};
cout<< "The first array is: "<< "\n";
int i;
for (i = 0; i<10; i++)
{cout<< B[i]<< " ";}
vector<int> KVec(B,B+10);
cout << "\n \n" << "The first vector is: " << endl;
showContents(KVec);
list<int> BList(B,B+10);
cout << "\n" << "The first list is: " << endl;
showContents(BList);
int BCopy [10];
cout<< "\n" <<"The second array is: "<< endl;
for(int i = 0; i <10; i++)
{
BCopy[i] = B[i];
BCopy[i] += 2;
cout<< BCopy[i]<< " ";
}
vector<int> KVec2(KVec);
cout<< "\n \n" << "The second vector is: "<< endl;
for (int i = 0; i<KVec2.size(); i++){
KVec2[i] += 3;
}
showContents(KVec2);
cout<< "\n" << "The second list is: "<< endl;
std::list<int> BList2 (BList);
for (std::list<int>::iterator b = BList.begin(); b!=BList.end(); ++b)
{
( *b += 5 );
showContents(BList2);
}
This is the code I have. I was able to correctly copy all the arrays, vectors , and lists and increasing the values of those accordingly. The only one I have not been able to increment in the list. My goal is to increment all the elements of the second list by 5. I have been using mulitple references to try and do it but I have tried everything and can not get it to work. Below I have my latest attempt at trying to increment all the values but that doesn't seem to work either so now I need help. That is the only thing left to do in this assignment so any help would be appreciated. Thank you.
Since my comment fixed your problem, I am converting it into an answer.
You copy constructed BList2 using values from BList (I am changing to brace initialization to avoid Most vexing parse). But then, you are iterating over values of BList again. Also, you don't need parentheses around *b += 5. Finally, your showContents function is probably meant to be outside of the loop.
std::list<int> BList2 {BList};
for (std::list<int>::iterator b = BList2.begin(); b != BList2.end(); ++b)
{
*b += 5;
}
showContents(BList2);

Unordered multimap finding all values

I would like to see whether it is possible to see all values that we have emplaced. For example:
#include <iostream>
#include <unordered_map>
using namespace std;
int main () {
unordered_multimap<string,int> hash;
hash.emplace("Hello", 12);
hash.emplace("World", 22);
hash.emplace("Wofh", 25);
for (int i = 1; i < 10; i++) {
hash.emplace("Wofh", i);
}
cout << "Hello " << hash.find("Hello")->second << endl;
cout << "Wofh " << hash.count("Wofh") << endl;
cout << "Wofh " << hash.find("Wofh")->second << endl;
return 0;
}
The output is :
$ ./stlhash
Hello 12
Wofh 10
Wofh 9
Whereas I want the last line to show from 25,1,2... to 9. Apparently find only takes first and second pointer as first is the value and second is the corresponding value. Is there any way to do this?
The operation you need is called equal_range
Example from the cplusplus.com:
// unordered_multimap::equal_range
#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
typedef std::unordered_multimap<std::string,std::string> stringmap;
int main ()
{
stringmap myumm = {
{"orange","FL"},
{"strawberry","LA"},
{"strawberry","OK"},
{"pumpkin","NH"}
};
std::cout << "Entries with strawberry:";
auto range = myumm.equal_range("strawberry");
for_each (
range.first,
range.second,
[](stringmap::value_type& x){std::cout << " " << x.second;}
);
return 0;
}

How can I print both the key and the value in a map?

When I try to print with it.first, it.second it does not work,
Are these even valid functions?
#include <iostream>
#include <string>
#include <map>
using namespace std;
int main()
{
map<string, int> workers;
workers["John"] = 1;
workers["Frank"] = 2;
for(map<string, int>::iterator it = workers.begin(); it != workers.end(); ++it) {
cout<<it.first()<<":"<<it.second()<<endl;
}
return 0;
}
first and second are no member functions, they are plain member objects:
cout << it->first << ":" << it->second << endl;
Note no parens, those are not function calls.

Traverse a List Using an Iterator?

I need sample for traversing a list using C++.
The sample for your problem is as follows
#include <iostream>
#include <list>
using namespace std;
typedef list<int> IntegerList;
int main()
{
IntegerList intList;
for (int i = 1; i <= 10; ++i)
intList.push_back(i * 2);
for (IntegerList::const_iterator ci = intList.begin(); ci != intList.end(); ++ci)
cout << *ci << " ";
return 0;
}
To reflect new additions in C++ and extend somewhat outdated solution by #karthik, starting from C++11 it can be done shorter with auto specifier:
#include <iostream>
#include <list>
using namespace std;
typedef list<int> IntegerList;
int main()
{
IntegerList intList;
for (int i=1; i<=10; ++i)
intList.push_back(i * 2);
for (auto ci = intList.begin(); ci != intList.end(); ++ci)
cout << *ci << " ";
}
or even easier using range-based for loops:
#include <iostream>
#include <list>
using namespace std;
typedef list<int> IntegerList;
int main()
{
IntegerList intList;
for (int i=1; i<=10; ++i)
intList.push_back(i * 2);
for (int i : intList)
cout << i << " ";
}
If you mean an STL std::list, then here is a simple example from http://www.cplusplus.com/reference/stl/list/begin/.
// list::begin
#include <iostream>
#include <list>
int main ()
{
int myints[] = {75,23,65,42,13};
std::list<int> mylist (myints,myints+5);
std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it != mylist.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
now you can just use this:
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> intList;
for (int i = 1; i <= 10; ++i)
intList.push_back(i * 2);
for (auto i:intList)
cout << i << " ";
return 0;
}