Generic function in C++ for removing duplicates - c++

I have to create a generic function that removes all duplicates in a vectorInt a vectorBook which is a class i created that has getYear and getName functions. I'm not sure how to make the the function because the vectorInt is compared because the Book gets compared with getName and getYear. Int is compared on one level while Book is compared on two levels.
template<class T> vector<T> removeDuplicates(vector<T> n){
for(unsigned int i = 0; i < n.size();i++){
T current = n.at(i);
for(unsigned int j = i + 1; j < n.size(); j++){
T compare = n.at(j);
if(current == compare)
n.erase(n.begin() + j);
}
}
return n;
}
Thanks for the help
EDIT:
Tried using this
template <class T> std::vector<T> removeDuplicates(std::vector<T> vec)
{
std::sort( vec.begin(), vec.end() );
vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() );
return vec;
}
but for books i keep getting an error
class Book {
public:
Book();
Book(std::string, int);
int getYear() const {
return year;
}
std::string getName() const {
return name;
}
bool operator==(Book const &);
private:
std::string name;
int year;
};

A pure STL version:
#include <algorithm>
template <class T> std::vector<T> removeDuplicates(std::vector<T> vec)
{
std::sort( vec.begin(), vec.end() );
std::vec.erase( std::unique( vec.begin(), vec.end() ), vec.end() );
return vec;
}
You can make it more efficient by taking and returning references rather than copies.
Code snarfed shamelessly from answer to this question.

As long as Book has a usable operator == implementation, this should work just fine. If not, then you will need to create a specialization for Book or add such an operator:
class Book
{
// ...
public:
bool operator==(Book const &);
};
bool Book::operator==(Book const & other)
{
return getName() == other.getName() && getYear() == other.getYear();
}
Note that you have an off-by-one error in your traversal -- if you do wind up deleting an item, the very next item will be skipped over. Consider using this loop instead:
for (vector<T>::iterator i = n.begin; i != n.end(); ++i) {
for (vector<T>::iterator j = i + 1; j != n.end(); /* */) {
if (*i == *j) {
n.erase(j++);
} else {
++j;
}
}
}

Related

Comparing function of binary_search

I am trying to run binary_search on vector of custom objects.
struct T{
string name;
T(string n):name(n){};
bool operator < ( T * n ) const {
return name < n -> name;
}
bool operator == ( T * n ) const {
return name == n -> name;
}
};
vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
bool has_3 = binary_search( t.begin(), t.end(), new T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
The comparation function should be just fine yet when i run the code has_3 equals to 0 = the element isnt present in vector. Is this problem caused by my overloading of < ? I see no reason why this shouldnt find the value. Considering the order of insertion into vector it should be sorted
Thanks for help.
There are several reasons why this shouldn't find the value:
The range must be sorted; your range is out of alphabetical order
Your comparison functionality is defined between T and T*, while you search a vector of T* for a T*.
You can fix the first problem by swapping "two" and "three", and the second problem by making a vector of T:
struct T{
string name;
T(string n):name(n){};
bool operator < ( const T &n ) const {
return name < n.name;
}
// operator == is not necessary for binary_search
};
int main() {
vector<T> t;
t.push_back(T("one"));
t.push_back(T("three"));
t.push_back(T("two"));
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
return 0;
}
Demo 1.
If you do have no way but to construct a vector of pointers, you have this ugly work-around available (I strongly recommend against it):
struct T{
string name;
T(string n):name(n){};
};
bool operator < (const T& l, const T *r) {
return l.name < r->name;
}
bool operator < (const T *l, const T &r) {
return l->name < r.name;
}
Now you can search like this:
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
Demo 2.
It's a really dumb requirement to work with a vector of pointers to dynamically allocated objects. But here is an approach that will work.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
};
// this is the comparater needed to work with pointers, but it should
// NOT be a member of T
bool pointer_comparer(const T *left, const T *right)
{
// this assumes both left and right point to valid objects
return left->name < right->name;
}
int main()
{
std::vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end(), pointer_comparer);
T *value_needed = new T("two");
bool has_3 = std::binary_search( t.begin(), t.end(), value_needed, pointer_comparer);
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// since we've been stupidly allocating objects, we need to release them
delete value_needed;
for (std::vector<T *>::iterator i = t.begin(), end = t.end();
i != end; ++i)
{
delete (*i);
}
// and since t now contains a set of dangling pointers, we need to discard them too
t.resize(0);
return 0;
}
Why do I say the requirement to work with a vector of pointers to dynamically allocated objects. Compare the above with an approach that works with a vector<T> rather than a vector<T *>.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
bool operator < (const T &) const
{
return name < n.name;
};
};
int main()
{
std::vector<T> t;
t.push_back(T("one"));
t.push_back(T("two"));
t.push_back(T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end());
bool has_3 = std::binary_search(t.begin(), t.end(), T("two"));
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// we need do nothing here. All objects use above will be properly released
return 0;
}
Note: I've written the above so it works with ALL C++ standards. Assuming C++11 and later, simplifications are possible in both cases.

Push_Front Pop_Back for C++ Vector

I'm trying to keep a vector of commands so that it keeps 10 most recent. I have a push_back and a pop_back, but how do I delete the oldest without shifting everything in a for loop? Is erase the only way to do this?
Use std::deque which is a vector-like container that's good at removal and insertion at both ends.
If you're amenable to using boost, I'd recommend looking at circular_buffer, which deals with this exact problem extremely efficiently (it avoids moving elements around unnecessarily, and instead just manipulates a couple of pointers):
// Create a circular buffer with a capacity for 3 integers.
boost::circular_buffer<int> cb(3);
// Insert threee elements into the buffer.
cb.push_back(1);
cb.push_back(2);
cb.push_back(3);
cb.push_back(4);
cb.push_back(5);
The last two ops simply overwrite the elements of the first two.
Write a wrapper around a vector to give yourself a circular buffer. Something like this:
include <vector>
/**
Circular vector wrapper
When the vector is full, old data is overwritten
*/
class cCircularVector
{
public:
// An iterator that points to the physical begining of the vector
typedef std::vector< short >::iterator iterator;
iterator begin() { return myVector.begin(); }
iterator end() { return myVector.end(); }
// The size ( capacity ) of the vector
int size() { return (int) myVector.size(); }
void clear() { myVector.clear(); next = 0; }
void resize( int s ) { myVector.resize( s ); }
// Constructor, specifying the capacity
cCircularVector( int capacity )
: next( 0 )
{
myVector.resize( capacity );
}
// Add new data, over-writing oldest if full
void push_back( short v )
{
myVector[ next] = v;
advance();
}
int getNext()
{
return next;
}
private:
std::vector< short > myVector;
int next;
void advance()
{
next++;
if( next == (int)myVector.size() )
next = 0;
}
};
What about something like this:
http://ideone.com/SLSNpc
Note: It's just a base, you still need to work a bit on it. The idea is that it's easy to use because it has it's own iterator, which will give you the output you want. As you can see the last value inserted is the one shown first, which I'm guessing is what you want.
#include <iostream>
#include <vector>
template<class T, size_t MaxSize>
class TopN
{
public:
void push_back(T v)
{
if (m_vector.size() < MaxSize)
m_vector.push_back(v);
else
m_vector[m_pos] = v;
if (++m_pos == MaxSize)
m_pos = 0;
}
class DummyIterator
{
public:
TopN &r; // a direct reference to our boss.
int p, m; // m: how many elements we can pull from vector, p: position of the cursor.
DummyIterator(TopN& t) : r(t), p(t.m_pos), m(t.m_vector.size()){}
operator bool() const { return (m > 0); }
T& operator *()
{
static T e = 0; // this could be removed
if (m <= 0) // if someone tries to extract data from an empty vector
return e; // instead of throwing an error, we return a dummy value
m--;
if (--p < 0)
p = MaxSize - 1;
return r.m_vector[p];
}
};
decltype(auto) begin() { return m_vector.begin(); }
decltype(auto) end() { return m_vector.end(); }
DummyIterator get_dummy_iterator()
{
return DummyIterator(*this);
}
private:
std::vector<T> m_vector;
int m_pos = 0;
};
template<typename T, size_t S>
void show(TopN<T,S>& t)
{
for (auto it = t.get_dummy_iterator(); it; )
std::cout << *it << '\t';
std::cout << std::endl;
};
int main(int argc, char* argv[])
{
TopN<int,10> top10;
for (int i = 1; i <= 10; i++)
top10.push_back(5 * i);
show(top10);
top10.push_back(60);
show(top10);
top10.push_back(65);
show(top10);
return 0;
}

recursive permutations using vector

I have this function that is suppose to return all possible permutation of integers inside the vector. The code is based from an existing code that does a permutation of strings, I tried to remodeled it to work on vectors but apparently, they dont work similarly as I thought..
I'll appreciate any help that you could offer thanks;
vector<vector<int>> permute(vector<int> &v1, vector<int> &v2){
vector<vector<int>> v;
if( v1.empty() )
{
v.push_back(v2);
return v;
}
for(auto it = v1.begin(); it != v1.end(); it++){
vector<int> temp1 = v1;
temp1.erase(it); //there's a runtime error on this line
vector<int> temp2 = v2;
temp2.push_back(*it);
permute(temp1, temp2);
}
return v;
}
This is the original code that permutes a string.
void string_permutation( std::string& orig, std::string& perm )
{
if( orig.empty() )
{
std::cout<<perm<<std::endl;
return;
}
for(int i=0;i<orig.size();++i)
{
std::string orig2 = orig;
orig2.erase(i,1);
std::string perm2 = perm;
perm2 += orig.at(i);
string_permutation(orig2,perm2);
}
}
Here you go:
template < typename T>
void vec_permute( std::vector<T> &orig, std::vector<T> &perm)
{
if(orig.empty())
{
for( auto &x : perm)
std::cout<<x;
std::cout<<"\n";
return;
}
for(typename std::vector<T>::size_type i=0;i <orig.size();++i)
{
std::vector<T> orig2(orig);
orig2.erase(std::find(orig2.begin(),orig2.end(),orig.at(i)));
std::vector<T> perm2(perm);
perm2.push_back(orig.at(i));
vec_permute(orig2,perm2);
}
}
Demo: http://coliru.stacked-crooked.com/a/01ded4b778aa4165
Iterators can only be used with the container that you instanciated them with

I cannot make a copy constructor for a bidirectional map

I am in my first year of c++ at university and in some days i have exam.
I work hard for this exam not only to succeed but to succeed with the best mark.
In this code that I post I have to make a bidirectional map which i was able to do and some other functions for it.
The problem comes when i try to make a copy constructor for this bidirectional map.
I know it is a little shameful to come to you guys with this minor problem but I last give a try.
If someone of you has patience to help me i will be very happy to succeed with high mark at my c++ exam.
So here is the header where i create a bidirectional map.This contains 2 maps: one stores the key and the value and other stores the value like key and the first key like the value. The problem comes when i have to do a copy constructor and I not have the optimal knowledge to do this.
#ifndef BIMAP_H_INCLUDED
#define BIMAP_H_INCLUDED
#include<map>
#include <utility>
template <class T>
class BidirectionalMap
{
public:
BidirectionalMap(){};
BidirectionalMap(typename std::multimap<T,T>::iterator beg, typename std::multimap<T,T>::iterator end)
{
m1.insert(beg,end
}
void insert(T a, T b)
{
m1.insert(std::pair<T,T> (a,b));
m2.insert(std::pair<T,T> (b,a));
}
BidirectionalMap& operator =(const BidirectionalMap &c)
{
m1=c.m1;
m2=c.m2;
return *this;
}
const T& at(const T &a) const
{
if(m2.find(a)!=m2.end()) return m2.at(a);
else return m1.at(a);
}
int count(const T &a) const
{
if(m2.find(a)!=m2.end()) return m2.count(a);
else if(m1.find(a)!=m1.end()) return m1.count(a);
else return 0;
}
void erase(const T &a)
{
if(m1.find(a)!=m1.end())
{
T b=m1[a];
m1.erase(a);
m2.erase(b);
}
else
{
T b=m2[a];
m2.erase(a);
m1.erase(b);
}
}
int size() const
{
return m1.size();
}
typename std::map<T,T>::const_iterator begin() const
{
return m1.begin();
}
typename std::map<T,T>::const_iterator end() const
{
return m1.end();
}
private:
std::map<T,T> m1;
std::map<T,T> m2;
};
#endif // BIMAP_H_INCLUDED
And here is the main() where i use that bidirectional map.Do not focus on 2,3,4 but only on 5 because just there I have no idea.
#include <map>
#include <functional>
#include <iostream>
#include <algorithm>
#include <string>
#include "bimap.h"
struct LengthSum
{
int length;
LengthSum():length(0) {}
void operator()(const std::pair<std::string, std::string>& p)
{
length += p.first.length();
length += p.second.length();
}
};
const int max = 1000;
int main()
{
int yourMark = 1;
// 2-es
BidirectionalMap<int> fun;
for( int i = 1; i <= max; ++i )
fun.insert( i, i + max );
BidirectionalMap<std::string> tel;
tel.insert( "Aniko", "+36(70)555-8124" );
tel.insert( "Botond", "+36(30)555-4321" );
const BidirectionalMap<std::string> ctel = tel;
if ( fun.at( 1 ) == (1 + max) &&
ctel.at( "+36(30)555-4321" ) == "Botond" )
{
yourMark = ctel.count( "Aniko" ) +
fun.count( max * 2 ) +
ctel.count( "Unknown" );
}
// 3-as
tel.erase( "+36(70)555-8124" );
if ( 0 == tel.count( "Aniko" ) &&
max == fun.size() )
{
yourMark = ctel.size() + tel.size();
}
// 4-es
const int l = std::for_each( ctel.begin(), ctel.end(), LengthSum() ).length;
yourMark = l/10;
// 5-os
std::map<double, double> md;
md[1.12] = 8.8;
md[5.4] = 7.5;
std::multimap<int, int> mmi;
mmi.insert( std::make_pair( 1, 2 ) );
mmi.insert( std::make_pair( 3, 6 ) );
mmi.insert( std::make_pair( 5, 8 ) );
//Here is the problem because i don`t know to do this :
const BidirectionalMap<int> b( mmi.begin(), mmi.end() );//??
const BidirectionalMap<double> bd( md.begin(), md.end() );//??
if ( b.at(8) == 5 )
{
yourMark = b.size() +
bd.size() +
b.count( 9 );
}
std::cout << "Your mark is " << yourMark;
std::endl( std::cout );
}
For the 2,3,4 marks i succeeded but when it comes for the best mark(5 in my country) i crashed.
So if you have the time and patience PLEASE help me :(
First of all, you are trying to copy a multimap into a map. Multimaps can have multiple items with the same index stored, while a map has only one item per index.
So, you may have to iterate over the incoming range and insert the map element wise into your maps. What you do if you have multiple indices stored in the multimap you have to decide for yourself.
Edit:
To be compatible with both map and multimap you can always make the iterator a template argument:
template<typename TIter>
BidirectionalMap(TIter beg, TIter end) {
for(TIter it = beg; it != end; ++it) {
// insert elements
}
}
I solved it like this with help from #MatthiasB
BidirectionalMap(Titer beg, Titer end)
{
for(Titer it = beg; it != end; ++it)
{
m1.insert(*it);
m2.insert(std::pair<T,T> (it->second,it->first));
}

How do I find an element position in std::vector?

I need to find an element position in an std::vector to use it for referencing an element in another vector:
int find( const vector<type>& where, int searchParameter )
{
for( int i = 0; i < where.size(); i++ ) {
if( conditionMet( where[i], searchParameter ) ) {
return i;
}
}
return -1;
}
// caller:
const int position = find( firstVector, parameter );
if( position != -1 ) {
doAction( secondVector[position] );
}
however vector::size() returns size_t which corresponds to an unsigned integral type that can't directly store -1. How do I signal that the element is not found in a vector when using size_t instead of int as an index?
Take a look at the answers provided for this question: Invalid value for size_t?. Also you can use std::find_if with std::distance to get the index.
std::vector<type>::iterator iter = std::find_if(vec.begin(), vec.end(), comparisonFunc);
size_t index = std::distance(vec.begin(), iter);
if(index == vec.size())
{
//invalid
}
First of all, do you really need to store indices like this? Have you looked into std::map, enabling you to store key => value pairs?
Secondly, if you used iterators instead, you would be able to return std::vector.end() to indicate an invalid result. To convert an iterator to an index you simply use
size_t i = it - myvector.begin();
You could use std::numeric_limits<size_t>::max() for elements that was not found. It is a valid value, but it is impossible to create container with such max index. If std::vector has size equal to std::numeric_limits<size_t>::max(), then maximum allowed index will be (std::numeric_limits<size_t>::max()-1), since elements counted from 0.
std::vector has random-access iterators. You can do pointer arithmetic with them. In particular, this my_vec.begin() + my_vec.size() == my_vec.end() always holds. So you could do
const vector<type>::const_iterator pos = std::find_if( firstVector.begin()
, firstVector.end()
, some_predicate(parameter) );
if( position != firstVector.end() ) {
const vector<type>::size_type idx = pos-firstVector.begin();
doAction( secondVector[idx] );
}
As an alternative, there's always std::numeric_limits<vector<type>::size_type>::max() to be used as an invalid value.
In this case, it is safe to cast away the unsigned portion unless your vector can get REALLY big.
I would pull out the where.size() to a local variable since it won't change during the call. Something like this:
int find( const vector<type>& where, int searchParameter ){
int size = static_cast<int>(where.size());
for( int i = 0; i < size; i++ ) {
if( conditionMet( where[i], searchParameter ) ) {
return i;
}
}
return -1;
}
If a vector has N elements, there are N+1 possible answers for find. std::find and std::find_if return an iterator to the found element OR end() if no element is found. To change the code as little as possible, your find function should return the equivalent position:
size_t find( const vector<type>& where, int searchParameter )
{
for( size_t i = 0; i < where.size(); i++ ) {
if( conditionMet( where[i], searchParameter ) ) {
return i;
}
}
return where.size();
}
// caller:
const int position = find( firstVector, parameter );
if( position != secondVector.size() ) {
doAction( secondVector[position] );
}
I would still use std::find_if, though.
Something like this, I think. find_if_counted.hpp:
#ifndef FIND_IF_COUNTED_HPP
#define FIND_IF_COUNTED_HPP
#include <algorithm>
namespace find_if_counted_impl
{
template <typename Func>
struct func_counter
{
explicit func_counter(Func& func, unsigned &count) :
_func(func),
_count(count)
{
}
template <typename T>
bool operator()(const T& t)
{
++_count;
return _func(t);
}
private:
Func& _func;
unsigned& _count;
};
}
// generic find_if_counted,
// returns the index of the found element, otherwise returns find_if_not_found
const size_t find_if_not_found = static_cast<size_t>(-1);
template <typename InputIterator, typename Func>
size_t find_if_counted(InputIterator start, InputIterator finish, Func func)
{
unsigned count = 0;
find_if_counted_impl::func_counter<Func> f(func, count);
InputIterator result = find_if(start, finish, f);
if (result == finish)
{
return find_if_not_found;
}
else
{
return count - 1;
}
}
#endif
Example:
#include "find_if_counted.hpp"
#include <cstdlib>
#include <iostream>
#include <vector>
typedef std::vector<int> container;
int rand_number(void)
{
return rand() % 20;
}
bool is_even(int i)
{
return i % 2 == 0;
}
int main(void)
{
container vec1(10);
container vec2(10);
std::generate(vec1.begin(), vec1.end(), rand_number);
std::generate(vec2.begin(), vec2.end(), rand_number);
unsigned index = find_if_counted(vec1.begin(), vec1.end(), is_even);
if (index == find_if_not_found)
{
std::cout << "vec1 has no even numbers." << std::endl;
}
else
{
std::cout << "vec1 had an even number at index: " << index <<
" vec2's corresponding number is: " << vec2[index] << std::endl;
}
}
Though I feel like I'm doing something silly... :X Any corrections are welcome, of course.
You probably should not use your own function here.
Use find() from STL.
Example:
list L;
L.push_back(3);
L.push_back(1);
L.push_back(7);
list::iterator result = find(L.begin(), L.end(), 7);
assert(result == L.end() || *result == 7);
Take a vector of integer and a key (that we find in vector )....Now we are traversing the vector until found the key value or last index(otherwise).....If we found key then print the position , otherwise print "-1".
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int>str;
int flag,temp key, ,len,num;
flag=0;
cin>>len;
for(int i=1; i<=len; i++)
{
cin>>key;
v.push_back(key);
}
cin>>num;
for(int i=1; i<=len; i++)
{
if(str[i]==num)
{
flag++;
temp=i-1;
break;
}
}
if(flag!=0) cout<<temp<<endl;
else cout<<"-1"<<endl;
str.clear();
return 0;
}
Get rid of the notion of vector entirely
template< typename IT, typename VT>
int index_of(IT begin, IT end, const VT& val)
{
int index = 0;
for (; begin != end; ++begin)
{
if (*begin == val) return index;
}
return -1;
}
This will allow you more flexibility and let you use constructs like
int squid[] = {5,2,7,4,1,6,3,0};
int sponge[] = {4,2,4,2,4,6,2,6};
int squidlen = sizeof(squid)/sizeof(squid[0]);
int position = index_of(&squid[0], &squid[squidlen], 3);
if (position >= 0) { std::cout << sponge[position] << std::endl; }
You could also search any other container sequentially as well.