Access the previous element inside the function of for_each - c++

I'm trying to implement the fibonacci sequence in C++17 using for_each
#include <list>
#include <algorithm>
using namespace std;
int main(int argc, char* argv[]) {
list<int> mylist = {1,2,3,4,5};
for_each( next(mylist.begin()), mylist.end(), [](int &n){n = n + prev(n);});
}
to access the previous element inside the function, prev doesn't work. How can I access the previous element inside the function? Thanks.

First, it's much simpler to use std::adjacent_difference for operations on consecutive elements.
If you really want to improve your understanding of std::for_each, then it's possible, but you will have to take responsibility for updating a shadow iterator yourself, as it's not possible to work back from an element to an iterator:
#include <algorithm>
#include <iostream>
#include <list>
int main()
{
std::list<int> v(15);
v.front() = 1;
auto it = v.begin();
auto prev = it;
auto current = *it++;
std::for_each(it, v.end(),
[&current,&prev](int& n){ std::swap(n, current); current = n+*prev++;});
for (auto n: v) {
std::cout << n << '\n';
}
}
However, if we use std::vector for our storage, then we do have a way to access the previous element, since vectors store their elements contiguously:
#include <algorithm>
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v(15);
v[0] = v[1] = 1;
std::for_each(v.begin()+2, v.end(),
[](int& n){ n = (&n)[-1] + (&n)[-2];});
for (auto n: v) {
std::cout << n << '\n';
}
}

Even if you could use prev to access the previous element, it's unclear how the posted algorithm would generate the expected result (a Fibonacci sequence), because the passed list is initialized as
list<int> mylist = {1, 2, 3, 4, 5};
The lambda would have added (if it worked) the value of the previous element (already modified!) to the current one, resulting in the sequence: 1, 2 + 1 = 3, 3 + 3 = 6, ...
It may be easier to use a stateful lambda and a different algorithm, like std::generate (or std::generate_n).
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
#include <list>
#include <utility>
template <class T>
auto make_fibonacci_generator(T first, T second)
{
return [prev = first, cur = second] () mutable {
return cur += std::exchange(prev, cur);
};
}
template <class OutIt, class T = typename OutIt::value_type>
auto gen_n_fibonacci_numbers(T first, T second, std::size_t n, OutIt dest)
{
if ( n == std::size_t(0) )
return dest;
*dest++ = first;
if ( n == std::size_t(1) )
return dest;
*dest++ = second;
if ( n == std::size_t(2) )
return dest;
return std::generate_n(dest, n - 2, make_fibonacci_generator(first, second));
}
template <class OutIt, class T = typename OutIt::value_type>
void gen_fibonacci_numbers(T first, T second, OutIt dest, OutIt dest_last)
{
if ( dest == dest_last )
return;
*dest++ = first;
if ( dest == dest_last )
return;
*dest++ = second;
if ( dest == dest_last )
return;
std::generate(dest, dest_last, make_fibonacci_generator(first, second));
}
int main()
{
std::list<unsigned int> numbers;
gen_n_fibonacci_numbers(0, 1, 20, std::back_inserter(numbers));
for (auto i : numbers)
std::cout << ' ' << i;
std::cout << '\n';
std::array<int, 10> nums;
gen_fibonacci_numbers(0, 1, nums.begin(), nums.end());
for (auto i : nums)
std::cout << ' ' << i;
std::cout << '\n';
}
Testable here.

Related

remove duplicates from sorted array, same solution with different code way has different output

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "hello_world.h"
using namespace std;
class Solution1 {
public:
int removeDuplicates(vector<int>& nums) {
return distance(nums.begin(), removeDuplicates(nums.begin(), nums.end(), nums.begin()));
}
template<typename InIt, typename OutIt>
OutIt removeDuplicates(InIt begin, InIt end, OutIt output){
while(begin != end){
*output++ = *begin;
begin = upper_bound(begin, end, *begin);
}
return output;
}
};
class Solution2 {
public:
int removeDuplicates(vector<int>& nums) {
vector<int>::iterator output = nums.begin();
while(nums.begin() != nums.end()){
*output++ = *nums.begin();
nums.begin() = upper_bound(nums.begin(), nums.end(), *nums.begin());
}
return distance(nums.begin(), output);
}
};
int main()
{
//helloworld test;
//test.print();
int num[3] = {1,1,2};
vector<int> nums(num, num + 3);
Solution2 so;
int a = so.removeDuplicates(nums);
cout<<a<<endl;
return 0;
}
In main function, when i use the class solution1, the code can remove duplicates numbers from the arrary [1 1 2] ,to output [1 2]. In order to simplify the code, I changed the solution1 to solution2, but the solution2 can not execute right output, anybody know the reason?
In this while loop
while(nums.begin() != nums.end()){
*output++ = *nums.begin();
nums.begin() = upper_bound(nums.begin(), nums.end(), *nums.begin());
}
you are always using the iterator nums.begin() in the condition and in this statement
*output++ = *nums.begin();
because this statement
nums.begin() = upper_bound(nums.begin(), nums.end(), *nums.begin());
does not change the iterator returned by a new call of nums.begin().
You need to introduce a variable of the iterator type before the loop like
auto it = nums.begin();
while( it != nums.end()){
*output++ = *it;
it = upper_bound( it, nums.end(), *it );
}
Here is a demonstrative program
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 2 };
size_t i = 0;
while ( v.begin() != v.end() )
{
v.begin() = std::upper_bound( v.begin(), v.end(), *v.begin() );
if ( ++i == 10 ) break;
}
std::cout << "i = " << i << '\n';
i = 0;
auto it = v.begin();
while ( it != v.end() )
{
it = std::upper_bound( it, v.end(), *it );
if ( ++i == 10 ) break;
}
std::cout << "i = " << i << '\n';
return 0;
}
Its output is
i = 10
i = 2
To erase duplicates after the loop use the member function erase like
nums.erase( output, nums.end() );
The same can be done using the standard algorithm std::unique. For example
nums.erase( std::unique( nums.begin(), nums.end() ), nums.end() );

Can non type template arguments done on stl containers?

template<typename T,int nSize>
T Sum(T (&parr)[nSize])
{
T sum=0;
for(int i = 0; i < nSize ;++i)
{
sum += parr[i];
}
return sum;
}
int _tmain(int argc, _TCHAR* argv[])
{
int nArr[] = {1,2,3,4};
int nSum = Sum(nArr);
std::cout<<"Sum :"<<nSum;
}
Can std::vector be used instead of array.Or can array be replaced by any of the stl containers?
Can std::vector be used instead of array.Or can array be replaced by
any of the stl containers?
No. It is not possible as they are different in their types. But you can generalize the given function in the following way.
Make a template function taking the begin and end iterators of the container. Then using std::accumulate, sum the elements up, which will work for any sequence containers as well as the arrays:
Following is an example code: (See live online)
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <numeric> // std::accumulate
#include <iterator> // std::iterator_traits, std::cbegin, std::cend
template<typename Iterator>
constexpr auto Sum(Iterator begin, const Iterator end) -> typename std::iterator_traits<Iterator>::value_type
{
using RetType = typename std::iterator_traits<Iterator>::value_type;
return std::accumulate(begin, end, RetType{});
}
int main()
{
int nArr[] = { 1,2,3,4 };
std::vector<int> vec{ 1,2,3,4 };
std::list<int> list{ 1,2,3,4 };
// now you can
std::cout << "Sum of array: " << Sum(std::cbegin(nArr), std::cend(nArr)) << "\n";
std::cout << "Sum of vec: " << Sum(std::cbegin(vec), std::cend(vec)) << "\n";
std::cout << "Sum of list: " << Sum(std::cbegin(list), std::cend(list)) << "\n";
}
Output:
Sum of array: 10
Sum of vec: 10
Sum of list: 10
template<typename T, int nSize>
T sum(std::array<T, nSize> const&);
would be the equivalent signature for std::array. As you see, signature differs already. Trying to do the same for std::vector is bound to fail:
template<typename T, int nSize>
T sum(std::vector<T> const&);
How would you be able to know at compile time already how many elements will reside in the vector??? You simply cannot. Even if you specified nSize in code explicitly, e. g. sum<std::vector<int>, 7>, the function then would always try to iterate over exactly seven elements, resulting in undefined behaviour if there are less and not counting the surplus ones if there are more...
The typical way to go is using begin and end iterators, just as the standard library does, too, for all of its algorithms:
template <typename Iterator>
auto sum(Iterator begin, Iterator end) -> std::remove_reference_t<decltype(*begin)>
{
using type = decltype(sum(begin, end)); // just not wanting to repeat all
// that remove_reference stuff...
type s = type();
for( ; begin != end; ++begin)
{
s += *begin;
}
return s;
}
You additionally could, based on this function, provide a generic overload for arbitrary containers then:
template <typename Container>
auto sum(Container const& c)
{
using std::begin;
using std::end;
return sum(begin(c), end(c));
}
If your compiler supports C++ 17 then you can write a single function with using if constexpr statement.
For example
#include <iostream>
#include <vector>
template<typename T>
auto Sum( const T &container )
{
if constexpr( std::is_array_v<std::remove_reference_t<T>> )
{
std::remove_extent_t<T> sum = 0;
for ( const auto &item : container )
{
sum += item;
}
return sum;
}
else
{
typename T::value_type sum = 0;
for ( const auto &item : container )
{
sum += item;
}
return sum;
}
}
int main()
{
int nArr[] = { 1, 2, 3, 4 };
int nSum = Sum( nArr );
std::cout << "Sum :"<<nSum << '\n';;
std::vector<int> v = { 1, 2, 3, 4 };
nSum = Sum( v );
std::cout << "Sum :"<<nSum << '\n';;
}
The program output is
Sum :10
Sum :10
However it is better to split the function into two functions: one for arrays and other for standard containers.
#include <iostream>
#include <vector>
template<typename T, size_t N>
auto Sum( const T ( &a )[N] )
{
T sum = 0;
for ( const auto &item : a )
{
sum += item;
}
return sum;
}
template<typename T>
auto Sum( const T &container )
{
typename T::value_type sum = 0;
for ( const auto &item : container )
{
sum += item;
}
return sum;
}
int main()
{
int nArr[] = { 1, 2, 3, 4 };
int nSum = Sum( nArr );
std::cout << "Sum :"<<nSum << '\n';;
std::vector<int> v = { 1, 2, 3, 4 };
nSum = Sum( v );
std::cout << "Sum :"<<nSum << '\n';;
}

How to find the indices of matching elements of sorted containers?

I'm trying to get the indices of one container where the elements match. Both containers are sorted in ascending order. Is there an algorithm or combo of algorithms that would place the indices of matching elements of sorted containers into another container?
I've coded an algorithm already, but was wondering if this has been coded before in the stl in some way that I didn't think of?
I would like the algorithm to have a running complexity comparable to the one I suggested, which I belive is O(min(m, n)).
#include <iterator>
#include <iostream>
template <typename It, typename Index_it>
void get_indices(It selected_it, It selected_it_end, It subitems_it, It subitems_it_end, Index_it indices_it)
{
auto reference_it = selected_it;
while (selected_it != selected_it_end && subitems_it != subitems_it_end) {
if (*selected_it == *subitems_it) {
*indices_it++ = std::distance(reference_it, selected_it);
++selected_it;
++subitems_it;
}
else if (*selected_it < *subitems_it) {
++selected_it;
}
else {
++subitems_it;
}
}
}
int main()
{
int items[] = { 1, 3, 6, 8, 13, 17 };
int subitems[] = { 3, 6, 17 };
int indices[std::size(subitems)] = {0};
auto selected_it = std::begin(items), it = std::begin(subitems);
auto indices_it = std::begin(indices);
get_indices(std::begin(items), std::end(items)
, std::begin(subitems), std::end(subitems)
, std::begin(indices));
for (auto i : indices) {
std::cout << i << ", ";
}
return 0;
}
We can use find_if to simplify the implementation of the function:
template<class SourceIt, class SelectIt, class IndexIt>
void get_indicies(SourceIt begin, SourceIt end, SelectIt sbegin, SelectIt send, IndexIt dest) {
auto scan = begin;
for(; sbegin != send; ++sbegin) {
auto&& key = *sbegin;
scan = std::find_if(scan, end, [&](auto&& obj) { return obj >= key; });
if(scan == end) break;
for(; scan != end && *scan == key; ++scan) {
*dest = std::distance(begin, scan);
++dest;
}
}
}
This doesn't make it that much shorter, but the code looks a little cleaner now. You're scanning until you find something as big as or equal to the key, and then you copy indicies to the destination as long as the source matches key.
maybe I misunderstodd the question. But there is a function in the algorithm library.
std::set_intersection
This does, what you want in one function. See:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
// Input values
std::vector<int> items{ 1,3,6,8,13,17 };
std::vector<int> subitems{ 3,6,17 };
// Result
std::vector<int> result;
// Do the work. One liner
std::set_intersection(items.begin(),items.end(), subitems.begin(),subitems.end(),std::back_inserter(result));
// Debug output: Show result
std::copy(result.begin(), result.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
If I misunderstood, then please tell me and I will find another solution.
EDIT:
I indeed misunderstood. You wanted the indices. Then maybe like this?
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using Iter = std::vector<int>::iterator;
int main()
{
// Input values
std::vector<int> items{ 1,3,6,8,13,17 };
std::vector<int> subitems{ 3,6,17 };
// Result
std::vector<int> indices{};
Iter it;
// Do the work.
std::for_each(subitems.begin(), subitems.end(), [&](int i) {it = find(items.begin(), items.end(), i); if (it != items.end()) indices.push_back(std::distance(items.begin(),it));});
// Debug output: Show result
std::copy(indices.begin(), indices.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
Unfortunately a very long "one-liner".
I need to think more . . .
The answer is yes but it will come with C++20:
you can use ranges for this purpose:
first make a view with some predicate you like:
auto result = items | ranges::view::filter(predicate);
then take the iterator to the original array from base, for example result.begin().base() will give you the iterator to the begin of result in the original array.
#include <algorithm>
#include <iostream>
#include <vector>
#include <iterator>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
int main()
{
std::vector<int> items = { 1, 3, 6, 8, 13, 17 };
std::vector<int> subitems = { 3, 6, 17 };
auto predicate = [&](int& n){
for(auto& s : subitems)
if(n == s)
return true;
return false;
};
auto result = items | ranges::view::filter(predicate);
for (auto& n : result)
{
std::cout << n << '\n';
}
for(auto it = result.begin(); it != result.end(); ++it )
std::cout << it.base() - items.begin() << ' ';
}
see the godbolt
By using std::set_intersection, defining an assignment_iterator class and a assignment helper, this is possible:
#include <iterator>
#include <iostream>
#include <algorithm>
#include <vector>
template <typename Transform>
class assignment_iterator
{
Transform transform;
public:
using iterator_category = std::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
assignment_iterator(Transform transform)
: transform(transform)
{}
// For some reason VC++ is assigning the iterator inside of std::copy().
// Not needed for other compilers.
#ifdef _MSC_VER
assignment_iterator& operator=(assignment_iterator const& copy)
{
transform.~Transform();
new (&transform) Transform(copy.transform);
return *this;
}
#endif
template <typename T>
constexpr assignment_iterator& operator=(T& value) {
transform(value);
return *this;
}
constexpr assignment_iterator& operator* ( ) { return *this; }
constexpr assignment_iterator& operator++( ) { return *this; }
constexpr assignment_iterator& operator++(int) { return *this; }
};
template <typename Transform>
assignment_iterator<Transform> assignment(Transform&& transform)
{
return { std::forward<Transform>(transform) };
}
int main()
{
int items[] = { 1, 3, 6, 8, 13, 17 };
int subitems[] = { 3, 6, 17 };
std::vector<int> indices;
std::set_intersection(std::begin(items), std::end(items)
, std::begin(subitems), std::end(subitems)
, assignment([&items, &indices](int& item) {
return indices.push_back(&item - &*std::begin(items));
})
);
std::copy(indices.begin(), indices.end()
, assignment([&indices](int& index) {
std::cout << index;
if (&index != &std::end(indices)[-1])
std::cout << ", ";
})
);
return 0;
}
Demo
It's more code, but maybe assignment is a more generic means to do other operations, that currently require a specific implementations like back_inserter and ostream_iterator, and thus be less code in the long run (e.g. like the other use above with std::copy)?
This should work properly all the time based on the documentation here:
elements will be copied from the first range to the destination range.
You can use std::find and std::distance to find the index of the match, then put it in the container.
#include <vector>
#include <algorithm>
int main ()
{
std::vector<int> v = {1,2,3,4,5,6,7};
std::vector<int> matchIndexes;
std::vector<int>::iterator match = std::find(v.begin(), v.end(), 5);
int index = std::distance(v.begin(), match);
matchIndexes.push_back(index);
return 0;
}
To match multiple elements, you can use std::search in similar fashion.

Is there a function like lower_bound that returns the last value instead of the first?

For example, if I have a sorted array
{1,1,1,1,1,4,5}
and I want to know the rightmost index of 1, is there a function that will allow me to do that? (Apart from reverse sorting the array)
This should work:
auto p = std::equal_range( std::begin(v), std::end(v), 1 );
if( p.first != p.second ) {
auto it = p.second - 1;
//...
}
live example
There's none so you should craft one on your own.
template<class Ctr, class Elem> auto rightmost(Ctr &&c, Elem &&e) {
using std::begin;
using std::end;
auto b{begin(c)};
auto retVal{std::upper_bound(b, end(c), e)};
return retVal == b? b : --retVal;
}
#include <iostream>
#include <array>
#include <algorithm>
#include <iterator>
int main()
{
std::array<int, 6> data({2,2,2,2,4,7});
auto it = std::upper_bound(data.begin(), data.end(), 2);
int index = std::distance(data.begin(), it) - 1;
std::cout << "index for last '2' is " << index << std::endl;
}
output:
index for last '2' is 3

can I make std::list insert new elements with order ? or got to use std::sort?

If I want to use std::list and that the new elements inserted to the list will be inserted to the right position in relation to a compare function - can I do it ?
or I have to use std::sort after each insertion?
You can use:
std::set if your elements a immutable
std::map if your elements have immutable keys, but should have mutable values
std::list and looking up the insertion position
std::list with std::lower_bound:
#include <algorithm>
#include <list>
#include <iostream>
int main()
{
std::list<int> list;
int values[] = { 7, 2, 5,3, 1, 6, 4};
for(auto i : values)
list.insert(std::lower_bound(list.begin(), list.end(), i), i);
for(auto i : list)
std::cout << i;
std::cout << '\n';
}
Alternatively you may populate an entire std::vector and sort it afterwards (Note: std::sort can not operate on std::list::iterators, they do not provide random access):
#include <algorithm>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> vector = { 7, 2, 5,3, 1, 6, 4};
std::sort(vector.begin(), vector.end());
for(auto i : vector)
std::cout << i;
std::cout << '\n';
}
Note: The performance of a list with manual lookup of the insertion position is the worst O(N²).
Yes you can. Try something like following, just change compare function and type if needed.
#include <list>
inline
int compare(int& a, int&b) {
return a - b;
}
template<typename T>
void insert_in_order(std::list<T>& my_list, T element, int (*compare)(T& a, T&b)) {
auto begin = my_list.begin();
auto end = my_list.end();
while ( (begin != end) &&
( compare(*begin,element) < 0 ) ) {
++begin;
}
my_list.insert(begin, element);
}
int main() {
std::list<int> my_list = { 5,3,2,1 };
my_list.sort(); //list == { 1,2,3,5}
insert_in_order<int>(my_list, 4, &compare); //list == {1,2,3,4,5}
}
You have three options:
Sort after every insertion
Find the right index and insert at that index
Use an std::set (recommended)
Example for third option:
#include <iostream>
#include <set>
int main ()
{
int myints[] = {75,23,65,42,13};
std::set<int> myset (myints,myints+5);
std::cout << "myset contains:";
for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
Output:
myset contains: 13 23 42 65 75