Randomly pick from a vector in C++? - c++

I have a vector that allows for duplicates, I want to randomly chose an element with the probability that represents how many times an element was repeated.
For example - for the vector below, 6 should have the highest probability of being chosen. I thought about using rand(), but I am not quiet sure how to incorporate the probability.
vector A = [ 0, 0, 2, 2, 4, 5, 1, 6, 6, 6]
thanks

I think you are on the right way for getting a custom distribution of values. See the following code which demonstrates the access to the vector. Hope it helps.
#include <cstdlib>
#include <iostream>
#include <ctime>
#include <vector>
int main()
{
std::vector<int> A { 0, 0, 2, 2, 4, 5, 1, 6, 6, 6 };
std::srand(std::time(0)); // use current time as seed for random generator
int random_pos = std::rand() % A.size(); // Modulo to restrict the number of random values to be at most A.size()-1
int random_val = A[random_pos];
}

Maybe something like this (untested!):
#include <vector>
#include <random>
#include <iostream>
int main()
{
std::vector<size_t> A{0, 0, 2, 2, 4, 5, 1, 6, 6, 6};
static thread_local std::mt19937 g{std::random_device{}()};
static thread_local std::uniform_int_distribution<size_t> d{0,A.size()};
std::cout << A[d(g)] << std::endl;
}

Related

get length of multidimensional array with different length in c++?

I have a multidimensional array and i'm trying to get the length of each column. But it's returning 20 for all of them.
int buttons[16][5] = {{0, 4, 1},{1, 0, 2, 5},{2, 1, 3, 6},{3, 2, 7},{4,0,5,8},{5,1,4,6,9},{6,2,5,7,10},{7,3,6,11},{8,4,9,12},{9,5,8,10,13},{10,6,9,11,14},{11,7,10,15},{12,8,13},{13,9,12,14},{14,10,13,15},{15,11,14}};
sizeof(buttons[0]);
You are declaring an C-style array where each element is an array of 5 int. Therefore, with sizeof(buttons[0]), you are getting the size of 5 ints. Usually, ints have a size of 4 bytes, hence you get 20. Only apparently has buttons[0] 3 elements: in fact, in your code, you initialize only the first 3 elements of buttons[0].
If you want a multidimensional array, where each "column" has different size, you should better use std::vector which can hold array of variable size. Then size() gives you the actual number of element.
Example code:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> buttons[16] = {{0, 4, 1},{1, 0, 2, 5},{2, 1, 3, 6},{3, 2, 7},{4,0,5,8},{5,1,4,6,9},{6,2,5,7,10},{7,3,6,11},{8,4,9,12},{9,5,8,10,13},{10,6,9,11,14},{11,7,10,15},{12,8,13},{13,9,12,14},{14,10,13,15},{15,11,14}};
std::cout << buttons[0].size();
}
Even better, you could use a vector of vector:
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> buttons = {{0, 4, 1},{1, 0, 2, 5},{2, 1, 3, 6},{3, 2, 7},{4,0,5,8},{5,1,4,6,9},{6,2,5,7,10},{7,3,6,11},{8,4,9,12},{9,5,8,10,13},{10,6,9,11,14},{11,7,10,15},{12,8,13},{13,9,12,14},{14,10,13,15},{15,11,14}};
std::cout << buttons[0].size();
}
You can't do that with arrays. You can do that with vectors:
vector<vector<int> > buttons = ...;
for (auto const& button : buttons) cout << button.size() << '\n';

Eigen: replicate items along one dimension without useless allocations

I have some vector vec and i want to obtain a new "expression" vec2 by copying values along dimension of vector
Eigen::VectorXf vec(5);
vec << 1, 2, 3, 4, 5;
const auto vec2 = vec.someAwesomeEigenMagic<3>();
//vec2 should contains (1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5)^T
//Not (1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5)^T
Of course i can create such vector manually or by using replicate + vectorization by Eigen::Map:
MatrixXf tmp = vec.replicate(1, 3).transpose();
const Map<VectorXf> vec2(tmp.data(), vec.rows() * 3, 1);
But i want vec2 to be some kind of "eigen template expression" without allication (vec can be quite big and i will call this routine quite often) and immediate computing of values. (vec contains per vertex weights and i want to use it for weighted least squares)
I thought about kronecker product trick with vector of ones, but i'm not sure is it optimized for product by ones. Also i prefer to avoid unsupported module
PS Sorry for my English
Using the devel branch you can use LinSpaced to generate the sequence of indices and then index the input vector:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main()
{
VectorXf vec(5);
vec << 1, 2, 3, 4, 5;
auto vecrep = vec(ArrayXi::LinSpaced(5*3,0,4));
cout << vecrep.transpose() << endl;
}
you can then wrap the key line within a free function returning auto, in c++14:
template<typename XprType>
auto magic_rep(const XprType &xpr, Index K) {
return xpr(Eigen::ArrayXi::LinSpaced(xpr.size()*K,0,xpr.size()-1));
}
and in main:
cout << magic_rep(vec,3).transpose() << endl;

OpenCV mean differentiate

I have a column-based(each column is a feature) large array(around 100M) which has dimensions of 75000(fixed)*number of samples
This is data vector:
std::vector<float> features;
I have used this code to calculate mean:
cv::Mat data(FEATURE_SIZE, features.size()/FEATURE_SIZE, CV_32F, &features[0]);
cv::reduce(data,dataMeans,1,CV_REDUCE_AVG);
FEATURE_SIZE is 75000 and features is a float vector which has all the data.
In order to calculate mean shift I used this:
data -= cv::repeat(dataMeans,1,features.size()/FEATURE_SIZE);
Which I think tries to create an array of same size with my features array and therefore giving me a bad allocation exception.
I just need that array to be mean differentiated. Is there any way to do it without copying, on the same memory location?
First, you messed up columns and rows.
Here a correct way to do what you want:
#define FEATURES_SIZE 3
int main()
{
vector<float> features = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
Mat1f data(features.size() / FEATURES_SIZE, FEATURES_SIZE, &features[0]);
Mat dataMeans;
cv::reduce(data, dataMeans, 1, CV_REDUCE_AVG);
data -= repeat(dataMeans, 1, FEATURES_SIZE);
}
However, probably you can't use opencv matrices with your dimensions.
You can instead use std functions:
// other includes
#include <algorithm>
#include <numeric>
#include <functional>
#define FEATURES_SIZE 3
int main()
{
vector<float> features = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
for(size_t i = 0; i<features.size(); i+= FEATURES_SIZE)
{
float cumsum = accumulate(features.begin() + i, features.begin() + i + FEATURES_SIZE, 0.f);
float avg = cumsum / FEATURES_SIZE;
transform(features.begin() + i, features.begin() + i + FEATURES_SIZE, features.begin() + i, bind2nd(std::minus<float>(), avg));
}
}
I don't know if this is the "minimum number of copies" optimal solution. Try with your large arrays and check if it is a problem.
Note: using namespace std; and using namespace cv used in my examples for brevity.
Hope it helps!

Are duplicates of the nth element always contiguous when using std::nth_element?

vector<int> data = {3, 1, 5, 3, 3, 8, 7, 3, 2};
std::nth_element(data.begin(), data.begin() + median, data.end());
Will this always result in:
data = {less, less, 3, 3, 3, 3, larger, larger, larger} ?
Or would a other possible outcome be:
data = {3, less, less, 3, 3, 3, larger, larger, larger} ?
I've tried it multiple times on my machine wich resulted in the nth values always being contiguous. But that's not proof ;).
What it's for:
I want to building a unique Kdtree but I have duplicates in my vector. Currently I'm using nth_element to find the median value. The issue is to select a unique/reconstructible median, without having to traverse the vector again. If the median values were contiguous I could choose a unique median, without much traversing.
No. The documentation does not specify such behavior, and with a few minutes of experimentation, it was pretty easy to find a test case where the dupes weren't contiguous on ideone:
#include <iostream>
#include <algorithm>
int main() {
int a[] = {2, 1, 2, 3, 4};
std::nth_element(a, a+2, a+5);
std::cout << a[1];
return 0;
}
Output:
1
If the dupes were contiguous, that output would have been 2.
I have just tried several not-so-simple examples, and on the third got non-contiguous output.
Program
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> a = {1, 3, 3, 2, 1, 3, 5, 5, 5, 5};
std::nth_element(a.begin(), a.begin() + 5, a.end());
for(auto v: a) std::cout << v << " ";
std::cout << std::endl;
}
with gcc 4.8.1 under Linux, with std=c++11, gives me output
3 1 1 2 3 3 5 5 5 5
while the n-th element is 3.
So no, the elements are not always contiguous.
I also think that even a simpler way, with no thinking of a good test case, was just generating long random arrays with many duplicate elements and checking whether it holds. I think it will break on the first or second attempt.

STL Container move selected elements

How to select elements with certain value from STL container and move them at the end of that container?
Considering you made a comment about wanting to use std::vector, I'd suggest using std::partition or std::stable_partition, i.e.:
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
int init_values[] = {1, 1, 7, 3, 19, 5, 5, 4, 5, 2, 5, 8, 9, 10, 5, 1};
std::vector<int> values(
init_values,
init_values + sizeof(init_values) / sizeof(int)
);
std::stable_partition(
values.begin(), values.end(),
std::bind1st(std::not_equal_to<int>(), 5)
);
std::copy(values.begin(), values.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << "\n";
return 0;
}
This code will move all elements of the vector that are equal to 5 to the end of the vector, keeping the relative order of the remaining elements in tact.
You could try using std::partition with a predicate that returns true for elements not equal to the target value. If you need to to preserve the relative order of the elements there is also std::stable_partition.