I'm currently trying to copy a part of a std::vector, starting with the first value until a sequence of values has been "encountered". I’m using mainly STL algorithms and especially std::find_if() (I know there are other ways to accomplish the goal stated in the first sentence, but I'm mainly doing this to understand the STL, so using them would be defeating the underlying purpose).
As an example, let's say a vector holding integer elements (originalvec in the code) is to be copied until first a 6 and then in direct succession a 7 is encountered. I know how to compare for the 6, and then I would like to compare in the same call of the lambda if behind the 6 there is a 7. I think (not sure) for that, I would need to get an iterator to the 6, then use either std::advance() or just operator++ on the iterator and compare the dereferenced value to 7. However, I do not know how to get an iterator to the 6/the number currently compared?
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector <int> originalvec = { 4, 8, 7, 6, 55, 2, 6, 7, 8 };
vector <int> newvec;
copy(originalvec.begin(),
find_if(originalvec.begin(), originalvec.end(), [](int curnum) {
return (curnum == 6);
}),
back_inserter(newvec));
//why does newvec.begin() (instead of back_inserter(newvec)) not work?
//current result: newvec = {4, 8, 7}
//wanted result : newvec = {4, 8, 7, 6, 55, 2}
/*wanted function is roughly in this style:
copy(originalvec.begin(),
find_if(originalvec.begin(), originalvec.end(), [](int curnum) {
return (curnum == 6 && [curnum* +1] == 7);
}),
back_inserter(newvec));
*/
return 0;
}
You can use std::adjacent_find in this case:
auto it = std::adjacent_find( originalvec.begin(), originalvec.end(), []( int i1, int i2 ) {
return i1 == 6 and i2 == 7;
} );
Live example
You can use a custom find function, for example (not tested)
template <typename It, typename T>
It find_succ(It begin, It end, T v1, T v2)
{
if (begin == end)
return end;
It next = begin;
++next;
while (next != end) {
if (*begin == v1 && *next == v2)
return begin;
++begin, ++next;
}
return end;
}
Related
Given two vectors of copyable elements and a predicate over those items, what is an efficient and idiomatic method for:
Removing matching items from the first vector
Appending matching items to the second vector
The following snippet reflects my current thinking, but it does require two passes over the source vector.
vector<int> source{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vector<int> target;
auto predicate = [](int n) { return n % 2 == 0; };
std::for_each(source.begin(), source.end(), [&predicate, &target](int n) {
if (predicate(n)) {
target.push_back(n);
}
});
auto it = std::remove_if(source.begin(), source.end(), predicate);
source.erase(it, source.end());
I'd use std::partition to partition sourceinto two parts.
auto itr = std::partition(source.begin(), source.end(), predicate);
target.insert(target.end(), itr, source.end());
source.resize(itr - source.begin());
If the ordering needs to remain the same then use stable_partition.
I agree with #acraig5075, that stable_partition, followed by copy and erase will do what you want.
However, if you don't want to shuffle elements around in the source container (probably a futile wish, IMHO), you can do it in a loop: (untested code)
auto itr = source.begin();
while (itr != source.end()) {
if (predicate(*itr)) {
target.push_back(*itr);
itr = source.erase(itr);
} else
++itr;
}
Note that this will "slide down" the elements of elements one at a time as they are moved into target, which is why I opined that avoiding this was probably foolish. (Note: If you're working with list, then it is less foolish)
For practice, I am trying to copy the first 4 entries different than 2 from a vector of integers using copy_if.
This seems to work but if there is a better way of writing this lambda then I'd like to learn the proper way. Cheers.
vector<int> first_vector = {2,8,50,2,4,5,9,12};
vector<int> second_vector (first_vector.size());
int count_elem=0;
auto it = copy_if(first_vector.begin(),first_vector.end(),second_vector.begin(),
[&count_elem]
(int i){
if(i!=2 && count_elem!=4)
{
count_elem++;
return 1;
}
return 0;});
Since you are not copying all of the values from first_vector to second_vector, you should not initialize second_vector to hold the same number of elements as first_vector. You are creating more elements than you want, where the extra elements are value-initialized to 0.
I would suggest reserve()'ing the size of second_vector instead and then use std::back_inserter as the destination iterator to copy to. That way, second_vector ends up with only the values you want pushed and nothing else.
That would also eliminate the need for the count_elem variable. You can use second_vector.size() to know how many values have been pushed into the vector.
std::vector<int> first_vector = {2, 8, 50, 2, 4, 5, 9, 12};
std::vector<int> second_vector;
second_vector.reserve(4);
std::copy_if(
first_vector.begin(), first_vector.end(),
std::back_inserter(second_vector),
[&](int i){
return ((i != 2) && (second_vector.size() < 4));
}
);
Do note, however, that this use of std::copy_if() will iterate through the entire first_vector, it will not stop iterating once 4 values have been pushed to second_vector. It would be more efficient to simply run your own loop instead so you can break it as soon as possible:
std::vector<int> first_vector = {2, 8, 50, 2, 4, 5, 9, 12};
std::vector<int> second_vector;
second_vector.reserve(4);
for(int i : first_vector) {
if (i != 2) {
second_vector.push_back(i);
if (second_vector.size() == 4)
break;
}
}
i want to iterate over a vector of ints and remove all even numbers.
Example:
std::vector<int> v = {5,2,9,3,8}
auto it = std::remove_if(v.begin(),v.end(),
std::bind(std::bind(std::equal_to<int>(),_1,0),
std::bind(std::modulus<int>(),_1,2)));
The expected result should be {5,9,3}
But it is {5,8,9,3,8}
I think the Iterator is already at the end before performing all functions in bind and remove.
I know how to solve it differently but i want to know how to use the nested form and how it works with iterators
In VS2015, your code leaves v containing {5, 9, 3, 3, 8}.
std::remove_if() returns an iterator to the first unused element in the vector, use that to truncate the vector :
v.erase(it, v.end());
After that, v contains {5, 9, 3}
On a side note, if you want to use a lambda instead of bind you can do it like this:
std::vector<int> v = { 5, 2, 9, 3, 8 };
auto it = std::remove_if(v.begin(), v.end(), [](int val) { return val % 2 == 0; });
v.erase(it, v.end());
I have list of ranges { start, end }, and a value (point) , now I am looking for effective way to get last n th index from range in which given value is present.
For example:
List: [ { 0, 4 }, {5, 10 }, {11, 14 }, {15, 20} , {21, 25} ]
n : 2
value: 22
So here, 22 is in range {21, 25 } which is at index 4 ( 0 based ).
and since n is 2, function should return index of {11, 14 } because this is n th range from matching range.
Here, I can write binary function easily since I have sorted list of ranges. But I do not want to write while / for , I am looking for some C++ 11 / 14 algorithms / lambdas if available, which can solve this issue.
What is an efficient solution?
I like Jan's answer, but since the appropriate solution is notably different if your data is known to be sorted, here's an answer for the question as-asked:
#include <cstddef>
#include <utility>
#include <stdexcept>
#include <algorithm>
#include <iterator>
template<typename RngT, typename ValT, typename OffsetT>
std::size_t find_prev_interval(RngT const& rng, ValT const& value, OffsetT const offset) {
using std::begin; using std::end;
auto const first = begin(rng), last = end(rng);
auto const it = std::lower_bound(
first, last, value,
[](auto const& ivl, auto const& v) { return ivl.second < v; }
);
// optional if value is *known* to be present
if (it == last || value < it->first) {
throw std::runtime_error("no matching interval");
}
auto const i = std::distance(first, it);
return offset <= i
? i - offset
: throw std::runtime_error("offset exceeds index of value");
}
As the implementation only needs forward-iterators, this will work for any standard library container or C-array; however for std::set<> or something like boost::containers::flat_set<>, you'll want to alter the logic to call rng.lower_bound() rather than std::lower_bound(). Also, replace exceptions with something like boost::optional if it is usual for offset to be too large to return a valid index.
Assuming that your point is stored as a std::pair and that returning an iterator instead of an index is acceptable:
template <typename container_t, typename value_t, typename n_t>
auto KailasFind(const container_t& vec, value_t value, n_t n) {
auto match = std::find_if(vec.begin(), vec.end(), [&](const auto& p) {
return value >= p.first && value <= p.second;
});
return match - n;
}
usage:
using point_t = std::pair<int, int>;
std::vector<point_t> vec {{0, 4}, {5, 10}, {11, 14}, {15, 20}, {21, 25}};
auto it_to_result = KailasFind(vec, 22, 2);
auto result = *it_to_result;
I would like to combine three variants of runlength encoding schemes (the runlengths are cumulated, hence the variant).
Let's start with two of them:
The first one contains a list of booleans, the second a list of counters. Let's say that the first looks as follows: (value:position of that value):
[(true:6), (false:10), (true:14), (false:20)]
// From 1 to 6, the value is true
// From 7 to 10, the value is false
// From 11 to 14, the value is true
// From 15 to 20, the value is false
The second looks as follows (again (value:position of that value)):
[(1:4), (2:8), (4:16), (0:20)]
// From 1 to 4, the value is 1
// From 5 to 8, the value is 2
// From 9 to 16, the value is 4
// From 17 to 20, the value is 0
As you can see, the positions are slightly different in both cases:
Case 1 : [6, 10, 14, 20]
Case 2 : [4, 8, 16, 20]
I would like to combine those "position arrays", by calculating their union:
[4, 6, 8, 10, 14, 16, 20]
Once I have this, I would derive from there the new schemes:
[(true:4), (true:6), (false:8), (false:10), (true:14), (false:16), (false:20)]
[(1:4), (2:6), (2:8), (4:10), (4:14), (4:16), (0:20)]
I would like to know: is there any C++ standard type/class which can contain the "arrays" [6, 10, 14, 20] and [4, 8, 16, 20], calculate their union and sort it?
Thanks
Dominique
You'll want to use std::set_union from <algorithm>.
I use a std::vector<int> here, but it can be any template type.
#include <iostream>
#include <array>
#include <algorithm>
int main() {
std::vector<int> a{6, 10, 14, 20};
std::vector<int> b{4, 8, 16, 20};
std::vector<int> c;
std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(c));
for(auto e: c) {
std::cout << e << ' ';
}
std::cout << '\n';
}
Here's the ideone
If you'd like to maintain only two std::vectors without introducing c, you could simply append b to a, sort the array, then call std::unique on a. There may be a clever way to do this in O(n), but here's the naïve approach:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> a{6, 10, 14, 20};
std::vector<int> b{4, 8, 16, 20};
a.insert(a.end(), b.begin(), b.end());
std::sort(a.begin(), a.end());
auto last = std::unique(a.begin(), a.end());
a.erase(last, a.end());
for(auto e: a) {
std::cout << e << ' ';
}
std::cout << '\n';
}
Here's the ideone
Finally, you can use std::inplace_merge instead of std::sort. In the worst case it's O(nlogn) like std::sort, but in the best case it's O(n). Quite an increase in performance:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> a{6, 10, 14, 20};
std::vector<int> b{4, 8, 16, 20};
auto a_size = a.size();
a.insert(a.end(), b.begin(), b.end());
// merge point is where `a` and `b` meet: at the end of original `a`.
std::inplace_merge(a.begin(), a.begin() + a_size, a.end());
auto last = std::unique(a.begin(), a.end());
a.erase(last, a.end());
for(auto e: a) {
std::cout << e << ' ';
}
std::cout << '\n';
}
Here's the ideone
I would like to know: is there any C++ standard type/class which can contain the "arrays" [6, 10, 14, 20] and [4, 8, 16, 20], calculate their union and sort it?
I guess you didn't do much research before asking this question. There's a class template that manages an ordered set, called set. If you add all the elements of two sets into a single set, you will have the union.
std::set<int> s1{6, 10, 14, 20};
std::set<int> s2{4, 8, 16, 20};
std::set<int> union = s1;
union.insert(s2.begin(), s2.end());
As hinted at by erip, there is an algorithm that only requires you to iterate both vectors once. As a precondition, both of them have to be sorted at the start. You can use that fact to always check which one is smaller, and only append a value from that vector to the result. It also allows you to remove duplicates, because if you want to add a value, that value will only be a duplicate if it is the last value added to the result vector.
I have whipped up some code; I haven't run extensive tests on it, so it may still be a little buggy, but here you go:
// Assume a and b are the input vectors, and they are sorted.
std::vector<int> result;
// We know how many elements we will get at most, so prevent reallocations
result.reserve(a.size() + b.size());
auto aIt = a.cbegin();
auto bIt = b.cbegin();
// Loop until we have reached the end for both vectors
while(aIt != a.cend() && bIt != b.cend())
{
// We pick the next value in a if it is smaller than the next value in b.
// Of course we cannot do this if we are at the end of a.
// If b has no more items, we also take the value from a.
if(aIt != a.end() && (bIt == b.end() || *aIt < *bIt))
{
// Skip this value if it equals the last added value
// (of course, for result.back() we need it to be nonempty)
if(result.size() == 0 || *aIt != result.back())
{
result.push_back(*aIt);
}
++aIt;
}
// We take the value from b if a has no more items,
// or if the next item in a was greater than the next item in b
else
{
// If we get here, then either aIt == a.end(), in which case bIt != b.end() (see loop condition)
// or bIt != b.end() and *aIt >= *bIt.
// So in either case we can safely dereference bIt here.
if(result.size() == 0 || *bIt != result.back())
{
result.push_back(*bIt);
}
++bIt;
}
}
It allows some optimizations in both style and performance but I think it works overall.
Of course if you want the result back in a, you can either modify this algorithm to insert directly into a, but it's probably faster to keep it like this and just a.swap(result) at the end.
You can see it in action here.