Does the interval_map (in icl) library provide support for deletion? Can I look up the range based on iterator and delete the range?
============ party.cpp from boost example ===============
partyp->add( // add and element
make_pair(
interval<ptime>::right_open(
time_from_string("2008-05-20 19:30"),
time_from_string("2008-05-20 23:00")),
mary_harry));
party += // element addition can also be done via operator +=
make_pair(
interval<ptime>::right_open(
time_from_string("2008-05-20 20:10"),
time_from_string("2008-05-21 00:00")),
diana_susan);
party +=
make_pair(
interval<ptime>::right_open(
time_from_string("2008-05-20 22:15"),
time_from_string("2008-05-21 00:30")),
peter);
==========
My question is can i add a remove statement like
party -=
interval<ptime>::right_open(
time_from_string("2008-05-20 20:10"),
time_from_string("2008-05-21 00:00"));
I just want to remove the range. Any method is fine.
I know this is an old post, but I had the same question and I've finally found an answer.
Looking at the docs I would guess that the Subtractability of an interval_map and the aggregate on overlap capabilities guarantee that the substraction works as a delete operation.
It turned out to be a very fruitful concept to propagate the addition
or subtraction to the interval_map's associated values in cases where
the insertion of an interval value pair into an interval_map resulted
in a collision of the inserted interval value pair with interval value
pairs, that are already in the interval_map. This operation
propagation is called aggregate on overlap.
Let's say I have to match intervals of unix timestamps to some record ids (integers).
Working from this answer I've come up with this MWE:
// interval_map_mwe.cpp
#include <map>
#include <set>
#include <climits>
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_map.hpp>
// Set of IDs that cover a time interval
typedef std::set<unsigned int> IDSet_t;
// interval tree from intervals of timestamps to a set of ids
typedef boost::icl::interval_map<time_t, IDSet_t> IMap_t;
// a time interval
typedef boost::icl::interval<time_t> Interval_t;
#include <iostream>
// from https://stackoverflow.com/a/22027957
inline std::ostream& operator<< (std::ostream& S, const IDSet_t& X)
{
S << '(';
for (IDSet_t::const_iterator it = X.begin(); it != X.end(); ++it) {
if (it != X.begin()) {
S << ',';
}
S << *it;
}
S << ')';
return S;
}
int main(int argc, const char *argv[])
{
(void)argc; // suppress warning
(void)argv; // suppress warning
IMap_t m;
IDSet_t s;
s.insert(1);
s.insert(2);
m += std::make_pair(Interval_t::right_open(100, 200), s);
s = IDSet_t();
s.insert(3);
s.insert(4);
m += std::make_pair(Interval_t::right_open(200, 300), s);
s = IDSet_t();
s.insert(5);
s.insert(6);
m += std::make_pair(Interval_t::right_open(150, 250), s);
std::cout << "Initial map: " << std::endl;
std::cout << m << std::endl;
// find operation
IMap_t::const_iterator it = m.find(175);
std::cout << "Interval that covers 175: ";
std::cout << it->first << std::endl;
std::cout << "Ids in interval: " << it->second << std::endl;
// partially remove 5 from interval (160,180)
s = IDSet_t();
s.insert(5);
m -= std::make_pair(Interval_t::right_open(160, 180), s);
std::cout << "map with 5 partially removed:" << std::endl;
std::cout << m << std::endl;
// completelly remove 6
s = IDSet_t();
s.insert(6);
// Note: maybe the range of the interval could be shorter if you can somehow obtain the minimum and maximum times
m -= std::make_pair(Interval_t::right_open(0, UINT_MAX), s);
std::cout << "map without 6: " << std::endl;
std::cout << m << std::endl;
// remove a time interval
m -= Interval_t::right_open(160, 170);
std::cout << "map with time span removed: " << std::endl;
std::cout << m << std::endl;
return 0;
}
Compiling with g++ 4.4.7:
g++ -Wall -Wextra -std=c++98 -I /usr/include/boost148/ interval_map_mwe.cpp
The output I get is
Initial map:
{([100,150)->{1 2 })([150,200)->{1 2 5 6 })([200,250)->{3 4 5 6 })([250,300)->{3 4 })}
Interval that covers 175: [150,200)
Ids in interval: (1,2,5,6)
map with 5 partially removed:
{([100,150)->{1 2 })([150,160)->{1 2 5 6 })([160,180)->{1 2 6 })([180,200)->{1 2 5 6 })([200,250)->{3 4 5 6 })([250,300)->{3 4 })}
map without 6:
{([100,150)->{1 2 })([150,160)->{1 2 5 })([160,180)->{1 2 })([180,200)->{1 2 5 })([200,250)->{3 4 5 })([250,300)->{3 4 })}
map with time span removed:
{([100,150)->{1 2 })([150,160)->{1 2 5 })([170,180)->{1 2 })([180,200)->{1 2 5 })([200,250)->{3 4 5 })([250,300)->{3 4 })}
Note: The numbers in the MWE can be considered random. I find it easier to reason about the example with small numbers.
Related
I do not understand the result of the following code (C++20 compiled with g++-10):
#include <iostream>
#include <vector>
#include <algorithm>
#include <ranges>
int main() {
using namespace std;
auto v = vector<int>{0,1,2,3,4,5,6,7};
auto r = v | views::filter([](int n) {return n % 3 == 0;});
ranges::generate(r,[]() { return 2; });
auto s = v | views::filter([](int n) {return n % 3 == 0;});
cout << "v: ";
for(auto x: v) cout << x << " ";
cout << "\n";
cout << "r: ";
for (auto x: r) cout << x << " " ;
cout << "\n";
cout << "s: ";
for (auto x: s) cout << x << " " ;
cout << "\n";
}
On my machine, the result is:
v: 2 1 2 2 4 5 2 7
r: 2
s:
I understand the first (v) and the third lines (s): in v, integers divisible by 3 are replaced by 2 (first line) and thus afterwards no integer is divisible by 3 anymore. Thus the third line is empty.
But why does the second line (r) display a unique value 2 and is different from the third line ???
If I replace the 2 by 3 in the ranges::generate then the result is normal:
v: 3 1 2 3 4 5 3 7
r: 3 3 3
s: 3 3 3
Maybe the reason is trivial but I did not find any reason in the documentation...
You are violating [range.filter.iterator]/1:
Modification of the element a filter_view::iterator denotes is permitted, but results in undefined behavior if the resulting value does not satisfy the filter predicate.
Your predicate here is elements divisible by 3, and you're modifying all of those to be 2 - which does not satisfy the predicate. That's undefined behavior. Don't do that.
In your followup example, you're modifying elements, but they still satisfy the predicate - so this is fine.
The reason this is the case is that filter has to cache its begin() iterator to satisfy the amortized O(1) constant requirement. What ends up happening is that during the generate, the filter looks for the first element that satisfies the predicate (which in this case is the very first element, the 0). That result is cached.
You then overwrite that value to 2, which is no longer divisible by 3, but the filter's begin() still refers to it. Which is why it gets printed.
When you create a new filter, that one doesn't have its begin() cached yet so there's no such issue.
Example: chessboard has 64 fields, starting from 1 in top uppermost left box,
row 2, column 2 means its 10th box,
row 4, column 2 means its 26th box .....so on
Formula, trick to determine Row_column no from box number or vice versa?
I guess you mean that you have 8 boxes on each row?
This might do the trick:
#include <iostream>
#include <cmath>
const int totalNrOfBoxes = 64;
const float nrOfRows = std::sqrt(totalNrOfBoxes);
std::pair<int, int> getRowAndColumn(int boxNumber) {
int rowNumber = std::ceil(boxNumber / nrOfRows);
int columnNumber = (boxNumber - 1) % (int) nrOfRows; // we do -1 to avoid getting 0 when the boxNr is 8 or 16 or 32 for example
columnNumber += 1; // we add one number to the column number because we removed one from the box number
return std::make_pair(rowNumber, columnNumber);
}
int main()
{
std::pair<int, int> rowAndColumn = getRowAndColumn(11);
std::pair<int, int> rowAndColumn2 = getRowAndColumn(64);
std::pair<int, int> rowAndColumn3 = getRowAndColumn(1);
std::pair<int, int> rowAndColumn4 = getRowAndColumn(34);
std::pair<int, int> rowAndColumn5 = getRowAndColumn(7);
std::cout << rowAndColumn.first << " " << rowAndColumn.second << std::endl;
std::cout << rowAndColumn2.first << " " << rowAndColumn2.second << std::endl;
std::cout << rowAndColumn3.first << " " << rowAndColumn3.second << std::endl;
std::cout << rowAndColumn4.first << " " << rowAndColumn4.second << std::endl;
std::cout << rowAndColumn5.first << " " << rowAndColumn5.second << std::endl;
}
gives us the following output:
2 3
8 8
1 1
5 2
1 7
So basically what we do to determine the row number, is to divide the given box number by the number of rows, and take the ceil (finds the closest integer not less than n) out of that. Example: 26 / 8 = 3.25. We know that 26 is on the 4th row, so we need to take the closest integer not less than 3.25 which is 4.
For the column number we take the remainder. So for example with 12 it would return 4. The problem is that we start counting boxes at 1, so 16 % 8 would return 0, while we do want to get a value of 8. So that is why we say boxNumber - 1 (15 % 8 which returns 7) and add 1.
I'd like some suggestions for the most terse and 'functional' way to gather pairs of successive elements from a vector (1st and 2nd, 3rd and 4th, etc.) using modern C++. Assume the vector is of arbitrary but even length. For the examples I'm pulling together, I'm summing the elements of each pair but that's not the main problem. I should add I'll use STL only, no Boost.
In Python I can zip them into 2-tuples via an iterator with
s = range(1,11)
print([(x + y) for x,y in zip(*[iter(s)] * 2)])
In Perl 5 I can peel off pairs with
use List::Util qw/pairs sum/;
use feature 'say';
#s = 1 .. 10;
say sum #$_ foreach (pairs #s);
In Perl 6 I can shove them two at a time into a block with
my #s = 1 .. 10;
for #s -> $x, $y { say $x + $y; }
and in R I can wrap the vector into a 2-column array and sum the rows with
s <- 1:10
print(apply(matrix(s, ncol=2, byrow=TRUE), 1, sum))
I am not fluent in C++ and my solution uses for(;;). That feels too much like C.
#include <iostream>
#include <vector>
#include <numeric> // std::iota
int main() {
std::vector<int> s(10);
std::iota(s.begin(), s.end(), 1);
for (auto p = s.cbegin(); p != s.cend(); p += 2)
std::cout << (*p + *(p + 1)) << std::endl;
}
The output of course should be some variant of
3
7
11
15
19
Using range-v3:
for (auto v : view::iota(1, 11) | view::chunk(2)) {
std::cout << v[0] + v[1] << '\n';
}
Note that chunk(2) doesn't give you a compile-time-fixed size view, so you can't do:
for (auto [x,y] : view::iota(1, 11) | view::chunk(2)) { ... }
Without using range-v3 I was able to do this with either a function or a lambda template. I'll show the lambda version here.
#include <iostream>
#include <string>
#include <vector>
template<typename T>
auto lambda = [](const std::vector<T>& values, std::vector<T>& results) {
std::vector<T> temp1, temp2;
for ( std::size_t i = 0; i < values.size(); i++ ) {
if ( i & 1 ) temp2.push_back(values[i]); // odd index
else temp1.push_back(values[i]); // even index
}
for ( std::size_t i = 0; i < values.size() / 2; i++ )
results.push_back(temp[i] + temp[2]);
};
int main() {
std::vector<int> values{ 1,2,3,4,5,6 };
for (auto i : values)
std::cout << i << " ";
std::cout << '\n';
std::vector<int> results;
lambda<int>(values, results);
for (auto i : results)
std::cout << i << " ";
std::cout << '\n';
std::vector<float> values2{ 1.1f, 2.2f, 3.3f, 4.4f };
for (auto f : values2)
std::cout << f << " ";
std::cout << '\n';
std::vector<float> results2;
lambda<float>(values2, results2);
for (auto f : results2)
std::cout << f << " ";
std::cout << '\n';
std::vector<char> values3{ 'a', 'd' };
for (auto c : values3)
std::cout << c << " ";
std::cout << '\n';
std::vector<char> results3;
lambda<char>(values3, results3);
for (auto c : results3)
std::cout << c << " ";
std::cout << '\n';
std::vector<std::string> values4{ "Hello", " ", "World", "!" };
for (auto s : values4)
std::cout << s;
std::cout << '\n';
std::vector<std::string> results4;
lambda<std::string>(values4, results4);
for (auto s : results4)
std::cout << s;
std::cout << '\n';
return EXIT_SUCCESS;
}
Output
1 2 3 4 5 6
3 7 11
1.1 2.2 3.3 4.4
3.3 7.7
a d
┼
Hello World!
Hello World!
At the risk of sounding like I'm trying to be clever or annoying, I say this is the answer:
print(sums(successive_pairs(range(1,11))));
Now, of course, those aren't built-in functions, so you would have to define them, but I don't think that is a bad thing. The code clearly expresses what you want in a functional style. Also, the responsibility of each of those functions is well separated, easily testable, and reusable. It isn't necessary to use a lot of tricky specialized syntax to write code in a functional style.
I have just started using range based for loops to simplify my code when using templates. I have come across a strange error and am not sure if this is something that I am missing or if the compiler is making a mistake. I have written a piece of code to illustrate the issue that I am having as well as the output. These are shown below.
Note: I am using the Mingw64 compiler on windows g++ (rev5, Built by MinGW-W64 project) 4.8.1 compiled without optimization with the --std=c++11 flag.
Code:
#include <iostream>
#include <array>
#include <vector>
int main()
{
// Declares an array of size 5 and of type int and intialises.
std::array<int,5> x = {1,2,3,4,5};
std::vector<int> y = {1,2,3,4,5};
// Prints each element
std::cout << "Array:" << std::endl;
std::cout << "x" << "\t" << "i" << std::endl;
for (auto i : x)
{
std::cout << x[i] << "\t" << i << std::endl;
}
std::cout << "Vector" << std::endl;
std::cout << "y" << "\t" << "i" << std::endl;
for (auto i : y)
{
std::cout << y[i] << "\t" << i << std::endl;
}
std::cin.get();
std::cin.get();
return 0;
}
Output:
Array:
x i
2 1
3 2
4 3
5 4
0 5
Vector
y i
2 1
3 2
4 3
5 4
1313429340 5
I would assume that the last line of both the vector and array output is an overflow, and notice how i starts at one instead of zero?? I would have assumed it would behave as described here.
I think you have not understood the syntax correctly
for (auto i : x)
here i is not an index of an array, it is the actual element inside the vector x.
So it is doing its job correctly.
"i" is the actual value in the array and not the index. So it is printing x[1] to x[5] in the first column and 1 to 5 in the second column. To access the values just print "i".
for (auto i : x)
creates copies of elements in x to be used inside your for loop. Use an iterator instead to access elements by their index.
for (size_t i = 0; i < x.size(); i++) {
std::cout << x[i] << "\t" << i << std::endl;
}
How can I write code to generate a random number that falls between two different ranges?
Example: Generate a random number that is between 5 and 7 or between 10 and 12. Possible outcomes are 5, 6, 7, 10, 11, or 12.
UPDATE Second implementation added below
If you want to make this generic, you'll have to code it.
Two options come to mind:
discrete_distribution (just feed it 5,6,7,10,11,12)
generate numbers [0..6) and index into an array int arr[]={5,6,7,10,11,12}
The second:
Live On Coliru
#include <random>
#include <iostream>
int main()
{
using namespace std;
vector<int> arr = {5,6,7,10,11,12};
mt19937 prng { random_device {} () };
uniform_int_distribution<> dist(0, arr.size()-1);
int i = 10;
while (i--)
std::cout << arr[dist(prng)] << " ";
}
Prints
5 5 6 12 11 6 11 12 5 12
Or, similar of course
UPDATE
An alternative implementation that will scale for many segments or large segments, by using Boost Interval Container Library to efficiently represent the intervals that make up the domain:
Live On Coliru
template <typename T = int>
struct uniform_draw {
using set = boost::icl::interval_set<T>;
using ival = typename set::interval_type::type;
uniform_draw(std::initializer_list<ival> data)
: set_(make_set(data)), dist_(0, set_.size() - 1)
{ }
friend std::ostream& operator<<(std::ostream& os, uniform_draw const& ud) {
return os << ud.set_ << " (#samples:" << ud.set_.size() << ")";
}
template <typename Engine>
T operator()(Engine& engine) {
uintmax_t index = dist_(engine);
std::cout << " - index: " << index << " against " << set_ << "\n";
// I think this can be optimized. I just don't know how to elegantly do that / yet
for (auto& iv : set_) {
std::cout << " - index: " << index << " against " << iv << "\n";
if (index > size(iv)) {
index -= size(iv);
} else {
return iv.lower() + index;
}
}
throw std::range_error("uniform_draw");
}
private:
set make_set(std::initializer_list<ival> data) {
set r;
for (auto& el : data)
r.insert(el);
return r;
}
set const set_;
std::uniform_int_distribution<T> dist_; // TODO make_unsigned<T>?
};
Use it like your usual distribution:
mt19937 mt { random_device {} () };
uniform_draw<int> dist { {5, 7}, {10, 12} };
std::cout << dist << "\n";
for (int i = 0; i < 10; ++i)
std::cout << "RESULT: " << dist(mt) << "\n";
Prints e.g.:
{[5,7)[10,12)} (#samples:4)
7 7 6 11 6 6 7 7 7 6
Pick a random number 0 or 1. If this number is 0, pick a random number in the first range, otherwise pick a random number in the second range.
If you want each number in the two ranges to have equal probability, you could weight the first decision based on the sizes of the two ranges.
I see two ways to do this. Let's say your two ranges are [minA, maxA] and [minB, maxB] where maxA < minB (if not just swap the two ranges)
Solution 1:
1) Generate a random number X in [minA, maxB] first
2) if X falls (maxA,minB) goto 1)
3) At this point X is the output
Solution 2 (more efficient especially if the gap between the two ranges is big):
1) rangeA = maxA - minA, rangeB = maxB - minB;
2) generate a random number X within [0,rangeA+rangeB]
3) if X < rangeA then output minA+X else minB+X