c++ general int array and vector iterator - c++

In the following code, I need to define an iterator which can iterate on both vector<int> and int[100]. How to define mi here?
template<class arraytype>
void array_show(arraytype array, size_t arraySize)
{
// how to define mi????
for (mi = array; array != m.end(); array++)
std::cout << " " << *mi << std::endl;
}

Try the following
#include <iostream>
#include <vector>
#include <iterator>
template<class arraytype>
void array_show( const arraytype &array )
{
for ( const auto &x : array ) std::cout << x << ' ';
std::cout << std::endl;
}
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<int> v( std::begin( a ), std::end( a ) );
array_show( a );
std::endl( std::cout );
array_show( v );
std::endl( std::cout );
return 0;
}
The program output is
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Another approach is to use iterators. For example (Here are shown the both function definitions)
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template<class arraytype>
void array_show( const arraytype &array )
{
for ( const auto &x : array ) std::cout << x << ' ';
std::cout << std::endl;
}
template <class InputIterator>
void array_show( InputIterator first, InputIterator last )
{
typedef typename std::iterator_traits<InputIterator>::value_type value_type;
std::copy( first, last,
std::ostream_iterator<value_type>( std::cout, " ") );
std::cout << std::endl;
}
int main()
{
int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
std::vector<int> v( std::begin( a ), std::end( a ) );
array_show( std::begin( a ), std::end( a ) );
std::endl( std::cout );
array_show( std::begin( v ), std::end( v ) );
std::endl( std::cout );
return 0;
}
The program output is the same as above
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Instead of the algorithm std::copy you can write a loop yourself. For example
template <class InputIterator>
void array_show( InputIterator first, InputIterator last )
{
for ( ; first != last; ++first )
{
std::cout << *first << ' ';
}
std::cout << std::endl;
}

Define your function to accept the start and the end iterators. You can then use your function for any form of iterables
template<typename Iter>
void array_show(Iter begin, Iter end)
{
// how to define mi????
for (Iter it = begin; it != end; it++)
std::cout << " " << *it << std::endl;
}
You can then call your function as follows
int main(int argc, char *argv[]) {
std::vector<int> vec= { 3, 1, 4, 1, 5, 9, 2, 6 };
int arr[] = { 3, 1, 4, 1, 5, 9, 2, 6 };
array_show(vec.begin(), vec.end());
array_show(std::begin(arr), std::end(arr));
}
In case you would want to pass the array as a reference as well as a vector, you should create two different function overloads to support both. This probably looks like your intention as your function signature intended to accept the size as well as the object.
template<typename Ty, size_t size>
void array_show(Ty(&arr)[size])
{
for (size_t i = 0; i < size; i++)
std::cout << " " << arr[i] << std::endl;
}
and subsequently call it as
int arr[] = { 3, 1, 4, 1, 5, 9, 2, 6 };
array_show(arr);

If you need to use it the way you showed:
template<class arraytype>
void array_show(arraytype array, size_t arraySize)
{
auto end = &(array[arraySize]);
for (mi = &(array[0]); array != end; ++array)
std::cout << " " << *mi << std::endl;
}
As vector has defined operator[], construct &(array[...]) will work for both vector and plain array.
But preferably:
template <class Iter>
void array_show(Iter begin, Iter end)
{
for (Iter it = begin, it != end; ++it)
std::cout << " " << *it << std::endl;
}
and then:
vector<int> vi;
int ai[100];
//fill with data
array_show(vi.begin(). vi.end());
array_show(ai, ai + 100);

Here is an example below. The importantpart is to use arraytype& - a reference, this way regular array is not decayed to pointer - this way it is possible to read its size inside array_show.
template<class arraytype>
void array_show(arraytype& array, size_t arraySize)
{
// how to define mi????
for (auto mi = std::begin(array); mi != std::end(array); mi++)
std::cout << " " << *mi << std::endl;
}

Related

Make a common function for a "type" and the vector of "type" using templates in C++

I was writing functions and came across this situation:
void doSomeThing(std::vector<someType> vec)
{
for(element : vec)
{
// do Something different if it is in vector
}
}
void doSomeThing(someType element)
{
// do Something else if it was not a vector
}
I need them to be separate like above stated. I was wondering if there was a way using templates to deduce the type and do the processing accordingly?
Well, yes, it is possible.
For example, you could do;
template<class someType>
void doSomeThing( const someType &obj )
{
// do something assuming someType is not a vector of something
}
template<class someType>
void doSomeThing( const std::vector<someType> &obj )
{
// do something different if a vector<someType> is passed
}
int main()
{
int x = 24;
std::vector<int> a{1,2,3}; // assuming C++11 and later
doSomeThing(x); // will call a specialisation of the first form above
doSomething(a); // will call a specialisation of the second form above
}
Personally, I'd do it slightly differently though - instead of overloading for a vector, I'd overload for a pair of iterators. For example, assuming doSomething() is just function that prints to std::cout
template<class someType>
void doSomeThing( const someType &obj )
{
std::cout << obj;
}
template<class Iter>
void doSomeThing( Iter begin, Iter end)
{
while(begin != end)
{
std::cout << *begin << ' ';
++begin;
}
std::cout << '\n';
}
which will work with iterators from any standard container (e.g. specialisations of std::vector, std::list) or anything else that can provide a pair of valid iterators.
int main()
{
int x = 24;
std::vector<int> a{1,2,3}; // assuming C++11 and later
std::list<double> b {42.0, 45.0};
doSomeThing(x);
doSomething(std::begin(a), std::end(a));
doSomething(std::begin(b), std::end(b));
}
With just little changes you can do so
#include <iostream>
#include <vector>
template <typename T>
void doSomeThing(std::vector<T> vec)
{
for (element : vec)
{
// do Something different if it is in vector
}
}
template <typename T>
void doSomeThing(T element)
{
// do Something else if it was not a vector
}
For example you can write
template <class T>
void doSomeThing( const std::vector<T> &vec )
{
for ( const auto &element : vec )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
template <class T>
void doSomeThing( const T &obj )
{
for ( const auto &element : obj )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
Here is a demonstration program.
#include <iostream>
#include <vector>
#include <type_traits>
template <class T>
void doSomeThing( const std::vector<T> &vec )
{
std::cout << std::boolalpha
<< std::is_same_v<std::decay_t<decltype( vec )>, std::vector<T>>
<< '\n';
for ( const auto &element : vec )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
template <class T>
void doSomeThing( const T &obj )
{
std::cout << std::boolalpha
<< std::is_same_v<std::decay_t<decltype( obj )>, std::vector<T>>
<< '\n';
for ( const auto &element : obj )
{
std::cout << element << ' ';
}
std::cout << '\n';
}
int main()
{
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
doSomeThing( v );
int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
doSomeThing( a );
}
The program output is
true
0 1 2 3 4 5 6 7 8 9
false
0 1 2 3 4 5 6 7 8 9

Remove duplicate elements from std::vector but starting from the front?

How can I delete duplicate elements from a vector but starting from the front?
So
2 3 4 5 2 5 would become 3 4 2 5
1 5 3 1 would become 5 3 1
I would like the solution to be easy to read, and it would be nice if it had good performance as well.
If a container supports bidirectional iterators then it is unimportant from which side of the container you are trying to remove duplicate elements because you can use reverse iterators.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
template <typename ForwardIterator>
ForwardIterator remove_duplicates( ForwardIterator first, ForwardIterator last )
{
for ( ; first != last; ++first )
{
last = std::remove( std::next( first ), last, *first );
}
return last;
}
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 4, 3, 2, 1 };
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
v.erase( remove_duplicates( std::begin( v ), std::end( v ) ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
std::cout << '\n';
v.assign( { 1, 2, 3, 4, 5, 4, 3, 2, 1 } );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
v.erase( std::begin( v ), remove_duplicates( std::rbegin( v ), std::rend( v ) ).base() );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
The program output is
1 2 3 4 5 4 3 2 1
1 2 3 4 5
1 2 3 4 5 4 3 2 1
5 4 3 2 1
An asymptotically efficient algorithm (N log N):
Create a range of iterators each pointing to the original container
Sort the iterators with a stable sort. Use a comparison function that indirects through the iterator.
Remove consecutive duplicates (std::unique) using reverse iterator and similar custom comparison function.
std::remove_if from the vector with a predicate function that removes elements whose iterator isn't in the secondary container.
It's a bit more complex than the O(N*N) solution. Here is an example implementation. I cannot guarantee that it is correct:
template<class It, class Sentinel>
auto remove_duplicates(It first, Sentinel last)
{
std::vector<It> iterators;
auto iterator_generator = [it = first]() mutable {
return it++;
};
std::generate_n(
std::back_inserter(iterators),
last - first,
iterator_generator);
auto iterator_compare = [](const auto& l, const auto& r) {
return *l < *r;
};
std::stable_sort(
iterators.begin(),
iterators.end(),
iterator_compare);
auto iterator_eq = [](const auto& l, const auto& r) {
return *l == *r;
};
auto last_unique = std::unique(
iterators.begin(),
iterators.end(),
iterator_eq);
iterators.erase(last_unique, iterators.end());
auto keep_generator = [it = first]() mutable {
return it++;
};
std::vector<bool> remove(last - first, true);
for(auto it : iterators) {
auto index = it - first;
remove[index] = false;
}
auto remove_predicate = [index = 0, remove = std::move(remove)](const auto& el) mutable {
return remove[index++];
};
return std::remove_if(first, last, std::move(remove_predicate));
}
// usage with reverse iterators
v.erase(
v.rend().base(),
remove_duplicates(v.rbegin(), v.rend()).base());

How to sort array of pair <int, pair <int, int> >, by first element, but descending order?

I want to sort an array containing pair <int, pair <int, int> >, by the first value, in descending order.
I had
pair <int, pair<int, int> > adj[10];
which had values in it, unsorted.
When I used
sort(adj, adj + 10);
it would sort the array based on the adj[i].first value, in ascending order.
However, when I tried sorting in descending order
sort(adj, adj + 10, greater<int>());
It wasn't letting me.
Is there other way to sort by descending order?
You could write:
std::sort(std::begin(adj), std::end(adj),
std::greater<std::pair<int, std::pair<int, int>>>{});
In c++14, you could simplify this to:
std::sort(std::begin(adj), std::end(adj), std::greater<>{});
In c++17, you could simply it a little more:
std::sort(std::begin(adj), std::end(adj), std::greater{});
In c++20, you could simplify this much further:
std::ranges::sort(adj, std::greater{});
You can write a custom predicate using a lambda.
std::sort(std::begin(adj),
std::end(adj),
[](auto const& lhs, auto const& rhs)
{
return lhs.first > rhs.first;
});
Note that the above predicate only considers the first element. You could expand that to look at the further elements if you wanted more complex sorting.
A simple way is to use a lambda expression as for example
#include <utility>
#include <iterator>
#include <algorithm>
//...
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b.first < a.first;
} );
Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <functional>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 3;
std::pair <int, std::pair<int, int> > adj[N] =
{
{ 1, { 1, 2 } }, { 1, { 2, 1 } }, { 2, { 1, 1 } }
};;
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b.first < a.first;
} );
for ( const auto &p : adj )
{
std::cout << " { " << p.first << ", { "
<< p.second.first << ", "
<< p.second.second << " } } ";
}
std::cout << '\n';
return 0;
}
The program output is
{ 2, { 1, 1 } } { 1, { 1, 2 } } { 1, { 2, 1 } }
As you can see from the output if two elements of the array have equal values of the first member of an object of the type std::pair then values of the second member are not taken into account and can be unordered.
Another approach is to use the expression std::gretar<>(). That is to use the default template argument for the functional object std::greater. Here is a demonstrative program.
#include <iostream>
#include <utility>
#include <functional>
#include <iterator>
#include <algorithm>
int main()
{
const size_t N = 3;
std::pair <int, std::pair<int, int> > adj[N] =
{
{ 1, { 1, 2 } }, { 1, { 2, 1 } }, { 2, { 1, 1 } }
};;
std::sort( std::begin( adj ), std::end( adj ), std::greater<>() );
for ( const auto &p : adj )
{
std::cout << " { " << p.first << ", { "
<< p.second.first << ", "
<< p.second.second << " } } ";
}
std::cout << '\n';
return 0;
}
The program output is
{ 2, { 1, 1 } } { 1, { 2, 1 } } { 1, { 1, 2 } }
In this case if two elements have an equal value of the first member then they are ordered according to values of the second member.
If your compiler does not support the C++ 14 Standard then the same effect of using std::greater<> you can achieve using the following lambda expression.
std::sort( std::begin( adj ), std::end( adj ),
[]( const auto &a, const auto &b )
{
return b < a;
} );
since you are using c++14 here is how: sort using std::greater<>{}
std::pair <int, std::pair<int, int> > adj[3];
adj[0]=std::make_pair(10,std::make_pair(0,0));
adj[1]=std::make_pair(1,std::make_pair(0,0));
adj[2]=std::make_pair(7,std::make_pair(0,0));
std::sort(adj, adj+3, std::greater<>{});
std::cout << "Sorted \n";
for (auto x=0; x<3;++x)
std::cout << "x: " << adj[x].first << "\n";
return 0;

C++ STL alogrithm like 'comm' utility

Can someone point me, please, if where is some algorithms within STL to compute difference and intersection per one call in manner of unix comm utility?
int main()
{
//For example we have two sets on input
std::set<int>a = { 1 2 3 4 5 };
std::set<int>b = { 3 4 5 6 7 };
std::call_some_func(a, b, ... );
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
}
My current implementation uses 2 calls of 'std::set_difference' and one call of 'std::set_intersection'.
I think this is probably a reasonably efficient implementation:
Features:
a) operates in linear time.
b) works with all ordered container types for input and all iterator types for output.
c) only requires operator< to be defined on the contained type, as per stl algorithms on sorted ranges.
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
example:
#include <tuple>
#include <set>
#include <vector>
#include <unordered_set>
#include <iterator>
#include <iostream>
/// #pre l and r are ordered
template<class I1, class I2, class I3, class I4, class ITarget1, class ITarget2, class ITarget3>
auto comm(I1 lfirst, I2 llast, I3 rfirst, I4 rlast, ITarget1 lonly, ITarget2 both, ITarget3 ronly)
{
while (lfirst != llast and rfirst != rlast)
{
auto&& l = *lfirst;
auto&& r = *rfirst;
if (l < r) *lonly++ = *lfirst++;
else if (r < l) *ronly++ = *rfirst++;
else *both++ = (++lfirst, *rfirst++);
}
while (lfirst != llast)
*lonly++ = *lfirst++;
while (rfirst != rlast)
*ronly++ = *rfirst++;
}
int main()
{
//For example we have two sets on input
std::set<int>a = { 1, 2, 3, 4, 5 };
std::set<int>b = { 3, 4, 5, 6, 7 };
std::vector<int> left;
std::set<int> right;
std::unordered_set<int> both;
comm(begin(a), end(a),
begin(b), end(b),
back_inserter(left),
inserter(both, both.end()),
inserter(right, right.end()));
//So as result we need obtain 3 sets
//x1 = {1, 2} // present in a, but absent in b (difference)
//x2 = {3, 4, 5} // present on both sets (intersection)
//x3 = {6, 7} // present in b, but absent in a
std::copy(begin(left), end(left), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(both), end(both), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
std::copy(begin(right), end(right), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
}
example output (note that the 'both' target is an unordered set):
1, 2,
5, 3, 4,
6, 7,
There is no single function to do that, you'd have to call the three functions you mentioned, or write something yourself. That being said, here's my attempt, though I'm not sure it's going to be any faster than the three step method you've already described
#include <algorithm>
#include <iostream>
#include <iterator>
#include <set>
template <typename T>
void partition_sets(std::set<T> const& a,
std::set<T> const& b,
std::set<T>& difference_a,
std::set<T>& difference_b,
std::set<T>& intersection)
{
std::set_intersection(begin(a), end(a),
begin(b), end(b),
std::inserter(intersection, intersection.begin()));
std::copy_if(begin(a), end(a), std::inserter(difference_a, difference_a.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
std::copy_if(begin(b), end(b), std::inserter(difference_b, difference_b.begin()), [&intersection](int i)
{
return intersection.find(i) == intersection.end();
});
}
Running your example
int main()
{
//For example we have two sets on input
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
std::set<int> x1;
std::set<int> x2;
std::set<int> x3;
partition_sets(a, b, x1, x2, x3);
std::cout << "a - b\n\t";
for (int i : x1)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "b - a\n\t";
for (int i : x2)
{
std::cout << i << " ";
}
std::cout << "\n";
std::cout << "intersection\n\t";
for (int i : x3)
{
std::cout << i << " ";
}
}
produces the output
a - b
1 2
b - a
6 7
intersection
3 4 5
Just write a wrapper for the three calls of the algorithms.
For example
#include <iostream>
#include<tuple>
#include <set>
#include <iterator>
#include <algorithm>
template <class T>
auto comm(const std::set<T> &first, const std::set<T> &second)
{
std::tuple<std::set<T>, std::set<T>, std::set<T>> t;
std::set_difference(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<0>(t), std::get<0>(t).begin()));
std::set_intersection(first.begin(), first.end(),
second.begin(), second.end(),
std::inserter(std::get<1>(t), std::get<1>(t).begin()));
std::set_difference(second.begin(), second.end(),
first.begin(), first.end(),
std::inserter(std::get<2>(t), std::get<2>(t).begin()));
return t;
}
int main()
{
std::set<int> a = { 1, 2, 3, 4, 5 };
std::set<int> b = { 3, 4, 5, 6, 7 };
auto t = comm(a, b);
for (auto x : std::get<0>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<1>(t)) std::cout << x << ' ';
std::cout << std::endl;
for (auto x : std::get<2>(t)) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The program output is
1 2
3 4 5
6 7

Show every container element with for_each function

I like to understand more about templates. I tried to write my own function, that shows every container element.
void show_element(int i){
std::cout << i << endl;
}
int main(){
int dataarr[5]={1,4,66,88,9};
vector<int> data(&daten[0],&daten[0]+5);
std::for_each(data.begin(),data.end(),show_element)
...
My show_element function isn't generic yet. How do i have to write it, so that i can use it for different container-types?
template <typename T>
using type = typename T::value_type;
void show_element(type i){ //type i must be sthg like *data.begin()
std::cout << i << endl;
}
thanks a lot
Change to:
template <typename T>
void show_element(T const &i) { std::cout << i << std::endl; }
for_each applies the given function (e.g., show_element) on the result of dereferencing every iterator in the range [first, last), in order. So you don't need to take the value_type of the container.
Also in c++14 and above you could define a generic lambda:
auto show_element = [](auto const &i) { std::cout << i << std::endl; };
and use it as:
int arr[] = {1, 4, 66, 88, 9};
std::vector<int> data(arr, arr + sizeof(arr) / sizeof(int));
std::for_each(arr, arr + sizeof(arr) / sizeof(int), show_element);
LIVE DEMO
Instead of a function it is more flexible to use a class. In this case you can pass additional arguments to the functional object.
For example you could specify a stream where you are going to output the elements or a separator that will separate the elements in the stream.
The class can look the following way
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
template <typename T>
class show_elements
{
public:
show_elements( const std::string &separator = " ", std::ostream &os = std::cout )
: separator( separator ), os( os ) {}
std::ostream & operator ()( const T &value ) const
{
return os << value << separator;
}
protected:
std::string separator;
std::ostream &os;
};
int main()
{
int arr[] = { 1, 4, 66, 88, 9 };
std::vector<int> v( arr, arr + sizeof( arr ) / sizeof( *arr ) );
std::for_each( v.begin(), v.end(), show_elements<int>() );
std::cout << std::endl;
}
The program output is
1 4 66 88 9
Another simple way is to use range-based for loop.
for(auto& element : container) {
cout<<element<<endl;
}