I've been using extensively boost::algorithm::find_if_backward to get a forward iterator to the last element in a range satisfying a predicate.
How do I accomplish the same task using Range-v3?
This is my attempt, which looks a bit clunky; and I'm not even sure is robust enough. Actually, as suggested in a comment, the code is not robust enough, because when no element is found, range_it_to_last_2 ends up being std::next(v.begin(), -1), which is undefined behavior, I believe.
#include <algorithm>
#include <boost/algorithm/find_backward.hpp>
#include <boost/hana/functional/partial.hpp>
#include <iostream>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/view/reverse.hpp>
using boost::algorithm::find_if_backward;
using ranges::find_if;
using ranges::views::reverse;
auto constexpr is_2 = boost::hana::partial(std::equal_to<>{}, 2);
int main() {
std::vector<int> v{0,1,2,2,2,3};
// What I have been doing so far:
auto boost_it_to_last_2 = find_if_backward(v, is_2);
// The Range-v3 analogous I could come up with, but it's ugly:
auto range_it_to_last_2 = std::next(find_if(v | reverse, is_2).base(), -1);
for (auto it = v.begin(); it <= boost_it_to_last_2; ++it) {
std::cout << *it << ' ';
} // prints 0 1 2 2 2
std::cout << std::endl;
for (auto it = v.begin(); it <= range_it_to_last_2; ++it) {
std::cout << *it << ' ';
} // prints 0 1 2 2 2
std::cout << std::endl;
}
Assuming you always know that a match is found, why not simplify to the following, getting the identical output:
Live On Godbolt
#include <algorithm>
#include <boost/algorithm/find_backward.hpp>
#include <boost/hana/functional/partial.hpp>
#include <fmt/ranges.h>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/view/subrange.hpp>
#include <range/v3/view/reverse.hpp>
using boost::algorithm::find_if_backward;
using ranges::find_if;
using ranges::views::reverse;
using ranges::subrange;
auto constexpr pred = boost::hana::partial(std::equal_to<>{}, 2);
int main() {
std::vector<int> v {0,1,2,2,2,3};
auto boost_match = find_if_backward(v, pred);
auto range_match = find_if(v | reverse, pred).base();
static_assert(std::is_same_v<decltype(boost_match), decltype(range_match)>);
fmt::print("boost: {}\nrange: {}\n",
subrange(v.begin(), boost_match+1),
subrange(v.begin(), range_match));
}
Prints
boost: {0, 1, 2, 2, 2}
range: {0, 1, 2, 2, 2}
(Some toy respellings for fun: https://godbolt.org/z/ccPKeo)
Related
This question already has answers here:
std::back_inserter for a std::set?
(2 answers)
Closed 12 months ago.
When I use transform on a set and use a vector to store the output, it works fine. But it doesn't seem to work the other way around.
This is the code that doesn't work:
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
int multiply(int a) {
return a * 2;
}
void print(int i) {
cout << i << " ";
}
int main() {
int mynumbers[] = { 3,9,2,4,1 };
vector<int> v1(mynumbers, mynumbers + 5);
set<int> s1(mynumbers, mynumbers + 5);
transform(v1.begin(), v1.end(), s1.begin(), multiply);
for_each(v1.begin(), v1.end(), print);
cout << endl;
for_each(s1.begin(), s1.end(), print);
}
As #molbdnilo pointed out:
The elements of a set are immutable.
Thus, existing elements cannot be overwritten.
However, it can be done with e.g. a std::insert_iterator:
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5 };
std::set<int> s;
std::transform(v.begin(), v.end(),
std::insert_iterator<std::set<int>>(s, s.begin()),
[](int x) { return x * 2; });
for (int x : s) std::cout << ' ' << x;
}
Output:
2 4 6 8 10
Live demo on coliru
As #JeJo already mentioned, std::inserter can be used.
Just pasting here the code with it.
set<int> s1;
transform(v1.begin(), v1.end(), inserter(s1, s1.begin()), multiply);
For the testing purpose, it does not matter, although it is not good to initialize the set s1 with vector v1 values, because transform adds/overwrites entries in the target container, and in your code the new values are getting mixed with old values (e.g. 4,9)
UPD:-
Value Instances
2 3
3 2
5 1
I want to limit the count to 1 for all the instances present in the multiset.
#include<bits/stdc++.h>
using namespace std;
int main() {
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(3);
p1.insert(2);
p1.insert(2);
for(auto itr : p1) {
if(p1.count(itr) > 1)
p1.erase(itr);
cout << itr;
}
}
How to fix this ?
My comment:
In that case, you should use a std::set<int> because that is actually what matches your requirement. You could use also a std::map<int, int> to map the key to the number of occurrences if you like.
OPs reply:
Can you add this to a full-fledged answer so that I can accept it for this question?
Here we go:
Just filtering duplicates:
#include <iostream>
#include <set>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once
using Table = std::set<int>;
Table table;
for (int value : sample) table.insert(value);
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 2
Value 3
Value 5
Demo on coliru
Counting the number of occurrences:
#include <iostream>
#include <map>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once but count the number of occurrences
using Table = std::map<int, unsigned>;
Table table;
for (int value : sample) ++table[value];
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry.first << " (" << entry.second << " times)\n";
}
}
Output:
Value 2 (3 times)
Value 3 (2 times)
Value 5 (1 times)
Demo on coliru
The trick:
The std::map::operator[] inserts an element if the key is not yet there. This element (in this case std::pair<const int, unsigned>) is default initialized which grants that it starts as { key, 0 }.
So, there are two cases:
The key is not yet there:
The element is created as { key, 0 } and the value (.second of the element) is incremented immediately which results in { key, 1 }.
The key is already there:
The value (.second of the element) is incremented again.
A variation on filtering duplicates:
This keeps the original input order but removes repetitions (by book-keeping in a separate std::set).
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator iterRead = sample.begin();
Sample::iterator iterWrite = sample.begin();
for (; iterRead != sample.end(); ++iterRead) {
if (table.insert(*iterRead).second) *iterWrite++ = *iterRead;
}
sample.erase(iterWrite, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 5
Value 2
Value 3
Demo on coliru
The trick:
std::set::insert() returns a pair of iterator and bool.
The iterator points to the key in the set (inserted or already been there).
The bool denotes if the key was inserted (true) or was already there (false).
The other trick:
Just erasing every found duplicate from the std::vector would result in the worse complexity O(n²).
Hence, two iterators are used, one for reading and one for writing. Thereby, every input value which is not yet in the bookkeeping table (and hence occurs the first time) is written back, otherwise not.
So, every value which occurred the first time is shifted towards the beginning and appended to the previous values which occurred the first time each. Additionally, the iterWrite points past the last written element after the loop and can be used to erase the rest (which contains left input values which are all duplicates).
The complexity of this algorithm is O(n) – much better than the naive approach.
Btw. the standard algorithms std::remove(), std::remove_if() does it the same way.
Thus, the same algorithm could be achieved with std::remove_if():
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator last
= std::remove_if(sample.begin(), sample.end(),
[&](int value) { return !table.insert(value).second; });
sample.erase(last, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
like above
Demo on coliru
#include <iostream>
#include <set>
using namespace std;
int main()
{
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(4);
p1.insert(2);
p1.insert(2);
for (auto iter = p1.begin(); iter != p1.end();)
{
p1.count(*iter) > 1 ? iter = p1.erase(iter) : iter++;
}
for (auto & iter : p1)
{
cout << iter << ", ";
}
return 0;
}
Given the code below:
// This example demonstrates filtering and transforming a range on the
// fly with view adaptors.
#include <iostream>
#include <string>
#include <vector>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
using std::cout;
int main()
{
std::vector<int> const vi{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
using namespace ranges;
auto rng = vi | views::filter([](int i) { return i % 2 == 0; }) |
views::transform([](int i) { return std::to_string(i); });
// prints: [2,4,6,8,10]
cout << rng << '\n';
}
How do encapsulate the logic above into a specific function that returns a range I can pipe? I'm thinking a function that can take a range and output a range. I will need the type signature of a range and I'm not sure how to find out that type signature or write it out? Is there documentation on specifically how to do this and how do I find this out?
We have as input a vector, as an example
std::vector<std::int32_t> allnumbers{1,2,-3,4,5,-6,7,8,9};
We have a boolean condition, as an example output numbers have to be larger 3.
What we want is as output the longest subvector fullfilling the condition. All elements of the output have to have been connected in the input.
std::vector<std::int32_t> allnumbers{4,5,7,8,9};
Is wrong, as 5 and 7 have not been adjacent before (-6 between them).
std::vector<std::int32_t> allnumbers{4,5};
Is wrong, as it is not the longest subvector.
std::vector<std::int32_t> allnumbers{7,8,9};
Is finally correct.
How to write the algorithm elegantly with C++17 standard, possibly without using the Boost library? By elegantly I mean few lines of code with good readability. Utilizing prefarably as much as possible. Performance or memory consumption is here less of an issue. I think the "brute force" solution I post below already has here enough performance. One time iterate through input and only few iterators to keep track during exectuion.
The following is a working "brute force" solution:
#include <functional>
#include <iostream>
#include <stdint.h>
#include <vector>
std::vector<std::int32_t> longestConnectedVectorFullfillingPredicate(
std::function<bool(const std::int32_t)> predicate,
std::vector<std::int32_t> &inputVector)
{
auto currentIt = inputVector.begin();
auto endIt = inputVector.end();
auto beginLongestConnectedSubvector = endIt;
auto endLongestConnectedSubvector = endIt;
auto longestConnectedSubvectorLength = 0;
while (currentIt != endIt)
{
const auto currentBeginConnectedSubvector = std::find_if(
currentIt, endIt, [predicate](const std::int32_t &value) { return predicate(value); });
const auto currentEndConnectedSubvector = std::find_if(
currentBeginConnectedSubvector, endIt, [predicate](const std::int32_t &value) {
return !predicate(value);
});
const auto currentConnectedSubvectorLength =
std::distance(currentBeginConnectedSubvector, currentEndConnectedSubvector);
if (currentConnectedSubvectorLength > longestConnectedSubvectorLength)
{
longestConnectedSubvectorLength = currentConnectedSubvectorLength;
beginLongestConnectedSubvector = currentBeginConnectedSubvector;
endLongestConnectedSubvector = currentEndConnectedSubvector;
}
currentIt = currentEndConnectedSubvector;
}
return std::vector<std::int32_t>(beginLongestConnectedSubvector, endLongestConnectedSubvector);
}
int main()
{
const auto largerThree = [](std::int32_t value) { return value > 3; };
std::vector<std::int32_t> allnumbers{1, 2, -3, 4, 5, -6, 7, 8, 9};
auto result = longestConnectedVectorFullfillingPredicate(largerThree, allnumbers);
for (auto res : result)
{
std::cout << res << std::endl;
}
return 0;
}
This is quite a few lines... Would like to shorten it without loosing much readability.
You might like this, which does the following
include needed headers, define useful namespace aliases, and a couple of useful function objects
pipes allnumbers into group_by which puts all adjacent numbers greater than 3 in a range/chunk (all other numbers remain in singleton range each)
pipes that into filter which says goodby to the singletons with the number not greater than 3
then finds the longest range by using max_element to which an appropriate lambda is passed
#include <boost/hana/functional/on.hpp>
#include <boost/hana/functional/partial.hpp>
#include <boost/hana/functional/reverse_partial.hpp>
#include <boost/range/numeric.hpp>
#include <functional>
#include <iostream>
#include <range/v3/algorithm/max_element.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/group_by.hpp>
#include <range/v3/view/transform.hpp>
#include <vector>
using boost::hana::on;
using boost::hana::reverse_partial;
using namespace ranges::views;
using namespace ranges;
auto both = [](bool x, bool y){ return x && y; };
auto greater_than_3 = reverse_partial(std::greater<>{}, 3);
int main() {
std::vector<int> allnumbers{1,2,-3,4,5,-6,7,8,9};
auto chunks
= allnumbers
| group_by(both ^on^ greater_than_3)
| filter([](auto v){ return greater_than_3(v.front()); })
| transform(to_vector)
| to_vector;
auto result = *max_element(
chunks,
std::less<>{} ^on^ std::mem_fn(&decltype(allnumbers)::size));
for (auto i : result) {
std::cout << i << ',';
}
}
I would like to multiply a vector with a scalar. This vector was created using the accepted answer to this question of mine namely:
std::vector<int> n(N + 1);
std::iota(begin(n), end(n), 0);
and I would like to multiply this vector, n, with a scalar (specifically of type double, if it is relevant here) called npi.
I have seen this answer to a previous question here, but it wasn't all that helpful. The way I attempted to implement it was by adding:
std::transform(n.begin(), n.end(), n.begin(),
std::bind1st(std::multiplies<T>(),pin));
to my C++ program. This returned the compile error:
error: ‘T’ was not declared in this scope
std::bind1st(std::multiplies<T>(),pin));
I would like to call the vector created by multiplying this vector with a scalar npi, so please do not give me code that will call this new vector n (i.e., overwriting my existing n vector).
EDIT:
If it will placate whomever voted to close this question, here is my full program:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <cmath>
#include <utility>
#include <unistd.h>
#include <algorithm>
#include <numeric>
/*#include <armadillo>*/
using namespace std;
/*using namespace arma;*/
double N = 1000.0;
double x0 = 0;
double x1 = 100;
double pin = M_PI / double(N);
int main() {
std::vector<int> n(N + 1);
std::iota(begin(n), end(n), 0);
std::transform(n.begin(), n.end(), n.begin(),
std::bind1st(std::multiplies<T>(),pin));
for(double i: n)
{
std::cout << i << '\n' << std::scientific;
}
}
For vector<int> output, one way is:
auto npi = n;
for( auto& i: npi )
i *= pin;
If npi should be vector<double> (not clear from the question) then replace the first line with:
std::vector<double> npi( n.begin(), n.end() );
You need to replace T by the type contained in the vector, in this case int. However you can probably simplify your code by using a lambda function here instead:
#include <algorithm> // for std::transform
#include <cmath> // for M_PI
#include <iostream> // for std::cout etc
#include <numeric> // for std::iota
#include <vector> // for awesome
int main() {
std::vector<int> vec1(10);
std::iota(vec1.begin(), vec1.end(), 0);
int N = 42;
std::vector<double> vec2(vec1.size()); // vec2 needs to be as big or bigger than vec1
std::transform(vec1.begin(), vec1.end(), vec2.begin(),
[N](int i) { return i * M_PI / N; });
for (auto a : vec1)
std::cout << a << " ";
std::cout << std::endl;
for (auto a : vec2)
std::cout << a << " ";
std::cout << std::endl;
}
Here's an online example: http://melpon.org/wandbox/permlink/XrNxDND0steJmym8
If I have understood you correctly you need the following
std::vector<double> v;
v.reserve(n.size());
std::transform(n.begin(), n.end(), std::back_inserter( v ),
std::bind1st(std::multiplies<double>(), pin));
You can pass the scalar in the capture clause of the Lambda function and do the multiplication inside the lambda function itself
#include <algorithm>
#include <vector>
std::vector<int> foo;
std::vector<int> bar;
auto npi=4.0;
std::transform (foo.begin(), foo.end(), bar.begin(), foo.begin(), [&npi](auto& c){return c * npi;}