Let's say I have a set of vector<int>:
std::vector<int> a = {2,3,8,4,9,0,6,10,5,7,1};
std::vector<int> b = {6,10,8,2,4,0};
std::vector<int> c = {0,1,2,4,5,8};
I want to create a new vector, in such a way that only elements which are common to all input vectors are input into the new vector as follows:
std::vector<int> abc = {8,2,0,8}; // possible output, order doesn't matter
I have seen many questions asking for how to remove duplicates, but I wish to retain only duplicates.
Is there an existing efficient STL algorithm or construct that will do this for me, or do I need to write my own?
As mentioned, you can use an algorithm set_intersection to do this:
But you will also have to sort the vectors first
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> a = {0,1,2,3,4,5,6,7,8,9,10};
std::vector<int> b = {0,2,4,6,8,10};
std::vector<int> c = {0,1,2,4,5,8};
std::vector<int> temp;
std::vector<int> abc;
std::sort(a.begin(), a.end());
std::sort(b.begin(), b.end());
std::sort(c.begin(), c.end());
std::set_intersection(a.begin(), a.end(),
b.begin(), b.end(),
std::back_inserter(temp));
std::set_intersection(temp.begin(), temp.end(),
c.begin(), c.end(),
std::back_inserter(abc));
for(int n : abc)
std::cout << n << ' ';
}
LIVE DEMO
Related
I'm new to C++, I came from Swift background, and I'm thankful for your help in advance.
I have a vector that contains int values. Some of them are repeated.
My task here is to get the largest repeated value from the vector.
Example:
std::vector<int> myVector;
myVector.push_back(1);
myVector.push_back(8);
myVector.push_back(4);
myVector.push_back(4);
I need a function that returns 4 because it's the largest duplicate int in the vector.
Thanks again, and please, if you have any question, please ask it instead of downvoting.
Solution based only on std algorithms:
Sort the list using std::sort.
Iterate backwards over its elements and detect the first one that is equal to its predecessor using std::adjacent_find and reverse iterators.
I doubt it gets simpler than this. For your enjoyment:
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v{1,2,3,3,4,4,4,5,6,7,7,8};
std::sort(v.begin(), v.end());
auto result = std::adjacent_find(v.rbegin(), v.rend());
if(result == v.rend())
std::cout << "No duplicate elements found.";
else
std::cout << "Largest non-unique element: " << *result;
}
Live example on Coliru.
Properties:
Zero space overhead if the list can be sorted in place.
Complexity: O(N log(N)) less than comparisons and K equality comparisons where K is equal to the number of unique elements larger than the one you're after.
Lines of code making up the algorithm: 2
You could use a map, as someone who commented above, and then place the number of appearances of each element of the vector. Afterwards, you take the maximum element via a custom comparator.
Ideone
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
int largestRepeatingNumber(const std::vector<int> & vec)
{
std::map<int, int> counter;
std::for_each(std::begin(vec), std::end(vec), [&counter] (int elem) {
counter.find(elem) == counter.end() ? counter[elem] = 1 : ++counter[elem]; });
return std::max_element(std::begin(counter), std::end(counter), [] (auto lhs, auto rhs) {
if (lhs.second == rhs.second)
return lhs.first < rhs.first;
return lhs.second < rhs.second;
})->first;
}
int main()
{
std::vector<int> myVector;
myVector.push_back(1);
myVector.push_back(8);
myVector.push_back(4);
myVector.push_back(4);
myVector.push_back(3);
myVector.push_back(3);
std::cout << largestRepeatingNumber(myVector);
return 0;
}
I have used the lower bound and upper bound
so strategy is
1)Sort the original vector (so that can use unique function on it)
2)find unique (copy the unique values to a vector so that we can use it to find the values in original vector , not extra search)
3)Find the lower and upper bound value with max distance
for example 1 4 4 8
4 will have max distance
5)Store in map using the count as index (map is ordered so max duplicate value will be at the end )
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
int main()
{
std::vector<int> myVector,myvec,counter;
map<int,int> maxdupe;
myVector.push_back(1);
myVector.push_back(8);
myVector.push_back(4);
myVector.push_back(4);
sort(myVector.begin(),myVector.end());
std::unique_copy(myVector.begin(), myVector.end(), std::back_inserter(myvec));
std::copy(myvec.begin(), myvec.end(), std::ostream_iterator<int>(std::cout, " "));
cout<<endl;
for(auto i = myvec.begin(); i!=myvec.end();i++)
{
auto lower = std::lower_bound(myVector.begin(), myVector.end(), *i);
auto upper = std::upper_bound(myVector.begin(), myVector.end(), *i);
maxdupe[upper - lower] = *i;
}
for(auto i= maxdupe.begin();i!= maxdupe.end();i++)
{
cout<<i->first<<i->second<<endl;
}
return 0;
}
Output
1 4 8
18
24
Program ended with exit code: 0
I have two containers std::set and std::vector and my task is to return elements from std::vector which are present in std::set. What is the most effective way to achieve it?
Simple solution:
Iterate through elements of vector and call set.find on each and then vector.erase if not found.
How about just looking for every element? If your vector is not sorted, then there's no way around n log(n)
#include <algorithm>
std::vector<int> result;
for(auto&& el: myvector) {
auto it_found = myset.find(el);
if(it != myset.end())
result.push_back(*it_found);
}
Now result has all the elements that are in both.
PS: Haven't compiled the code, there might be slight errors.
You can use more STL :)
#include <algorithm>
#include <set>
#include <vector>
#include <iostream>
#include <iterator>
int main() {
std::vector<int> v {5, 4, 3, 2, 1};
std::set<int> s {1, 3, 5};
v.erase(std::remove_if(v.begin(), v.end(),
[&s](int a) { return s.find(a) == s.end(); }),
v.end());
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
}
Shortest way is probably to use std::set_intersection. But you should sort a vector to make it work:
int main()
{
std::set<int> s{1,2,3,4,5,6,7,8};
std::vector<int> v{7,5,10,9};
std::sort(v.begin(), v.end()); // should not bother you if vector is small
std::vector<int> intersection;
std::set_intersection(s.begin(), s.end(), v.begin(), v.end(), std::back_inserter(intersection));
for(int n : intersection)
std::cout << n << ' ';
}
Prints: 5 7
Depending on relative size of set and vector, remove_if may be the right thing...
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
std::set<int> s{1,2,3,4,5,6,7,8};
std::vector<int> v{7,5,10,9};
v.erase(std::remove_if(v.begin(), v.end(), [&](int e){return s.count(e) == 0;}), v.end());
for(int n : v)
std::cout << n << ' ';
}
If you look for the most cpu-effective way of doing this in terms of complexity, have additional memory and a good hash function, you can do it in O(n + m):
std::vector<int> v;
std::set<int> s;
std::unordered_set<int> us{s.cbegin(), s.cend(), s.size()};
v.erase(
std::remove_if(v.begin(), v.end(),
[&us] (const int entry) { return us.find(entry) == us.cend(); }),
v.end());
Explanation: you iterate over your set once (O(m)) to prepare unordered_set. Then you iterate through your vector once (O(n)), performing unordered_set::find (0(1)) each step. It gives you the resulting complexity of O(n+m).
Also, the size of unordered_set being equal to the size of set and a good hash function helps to reduce constant part in complexity of std::unordered_set::find.
See live example.
Bear in mind, however, that lower complexity doesn't necessarily mean faster execution in particular circumstances (for example, because of extra allocations).
If I had two lists A and B, how can I add all the elements of B to the beginning of list A, without "emptying" the B list. I basically want to just transfer copies of B list into the beginning of A list. I'm thinking about using insert and want to double check on the syntax.
I know if I was adding it to the end it would be:
A.insert(A.end(), B.begin(), B.end());
so to insert it at the beginning would it be:
A.insert(A.begin(), B.begin(), B.end());
??
That can be achieved with one line, using the fact a list can be iterated both ways.
copy(A.rbegin(), A.rend(), front_inserter(B));
Complete example (C++11 for list constructors and printing code, but answer is C++03 valid):
#include <list>
#include <iterator>
#include <algorithm>
#include <iostream>
int main() {
// Create lists
std::list<char> A = {'a','b'};
std::list<char> B = {'c','d'};
// Insert A at the beginning of B
copy(A.rbegin(), A.rend(), front_inserter(B));
// Print result
for(auto c : B)
std::cout << c;
std::cout << "\n";
return 0;
}
Make a temporary copy of the list you want to append without emptying, then splice the temporary list into the original. Here is and example.
#include <iostream>
#include <list>
#include <vector>
int main ()
{
std::list<int> mylist;
std::list<int>::iterator it;
std::list<int> otherList;
std::list<int> combinedList;
// set some initial values:
for (int i=1; i<=5; ++i) mylist.push_back(i); // 1 2 3 4 5
for (int i=6; i<=10; i++) otherList.push_back(i); // 6 7 8 9 10
std::list<int> temp = otherList;
combinedList = mylist;
it = combinedList.begin();
combinedList.splice(it, temp);
std::cout << "mylist contains:";
for (it=combinedList.begin(); it!=combinedList.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
std::cout<<"orignal appended list:"<<std::endl;
for(it=otherList.begin(); it!=otherList.end(); ++it)
std::cout<<' '<<*it;
std::cout<<'\n';
return 0;
}
http://ideone.com/e.js/Ol6Wk1
I am trying to find a way to copy elements of a vector to another vector.
int main()
{
std::vector<int> aVec{0,1,2,3,4};
std::vector<int>::iterator itBegin = aVec.begin();
std::vector<int>::iterator itEnd = aVec.begin()+3;
std::vector<int> aVecNew;
// How to insert elements ranging from itBegin till itEnd(including itEnd) to
// the vector aVecNew
return 0;
}
Most of the insert methods appear not to include itEnd. Is there a clean way to do this?
EDIT: If I am not sure ++itEnd is the end iterator or not. In such case it would fail. Is there any safer way without the mess ?
You can use std::copy from <algorithms> and std::back_inserter from <iterator>:
int main(int a, char**){
std::vector<int> aVec{ 0, 1, 2, 3, 4 };
std::vector<int>::iterator itBegin = aVec.begin();
std::vector<int>::iterator itEnd = aVec.begin() + 3;
std::vector<int> aVecNew;
std::copy(itBegin, itEnd, std::back_inserter(aVecNew));
return 0;
}
PS: Also, as it was mentioned in the comment, this code copies excluding itEnd. If you want to copy elements including itEnd, just increment its value by 1:
int main(int a, char**){
std::vector<int> aVec{ 0, 1, 2, 3, 4 };
std::vector<int>::iterator itBegin = aVec.begin();
std::vector<int>::iterator itEnd = aVec.begin() + 3;
std::vector<int> aVecNew;
std::copy(itBegin, ++itEnd, std::back_inserter(aVecNew));
return 0;
}
Some documentation on back_inserter and copy.
Beyond the ways already mentioned, std::vector has a constructor that will do exactly what you want (take the elements from range given begin and end iterators).
std::vector<int> aVecNew(itBegin, ++itEnd);
In the general case - the target vector does already exist - the copy onto a back_insert_iterator until just before ++itEnd is the right way, but in your case,
std::vector<int> aVecNew(itBegin, ++itEnd);
is the appropriate measure. std::vector has ctor #(4) for that; no reason to first create and then populate the vector here.
#include <vector>
#include <iostream>
#include <iterator> // ostream_iterator
#include <algorithm> // copy
int main()
{
std::vector<int> aVec{0,1,2,3,4}; // this is c++ of 2011 or later...
// ... thus this
std::vector<int>::iterator itBegin = aVec.begin();
std::vector<int>::iterator itEnd = aVec.begin() + 3;
// (if used) would at least be a case for "auto"
std::vector<int> aVecNew(itBegin, ++itEnd);
std::copy(aVecNew.begin(), aVecNew.end(),
std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return EXIT_SUCCESS;
}
output:
0 1 2 3
live at Coliru's
I am getting the run time error in following code. Please let me know can i copy vector elements in set?
#include <iostream>
#include <vector>
#include <set>
using namespace std;
int main()
{
vector<int> v;
set<int> kk;
set<int>::iterator itr;
for (int i = 0; i < 6; i++)
{
v.push_back(i * 2);
}
copy(v.begin(), v.end(), inserter(kk, itr));
}
You are not initialising itr:
set<int>::iterator itr = kk.begin();
Or remove itr entirely:
copy(v.begin(), v.end(), inserter(kk, kk.begin()));
In this instance, you could simply initialise kk thus (but if you want to add to kk follow the line above):
set<int> kk(v.begin(), v.end());
If the goal is to create a set from the vector elements (rather than update an already existing set that might have some elements in it), then do that, by using the constructor:
set<int> s(v.begin(), v.end());
You need to initialize the iterator.
set<int>::iterator itr = kk.end();
Try:
copy(v.begin(), v.end(),inserter(kk, kk.end() ));
// ^^^^^^^^ You need a real iterator.