Is there a way to shift array elements in C++ without using any loop like the below Python code which shifts the elements of the list just by manipulating list indices
def rotate(lst, n):
n = n % len(lst)
return lst[n:] + lst[:n]
> rotate([1,2,3,4,5], 1) # rotate forward
[2, 3, 4, 5, 1]
C++ standard algorithms also work with arrays, so you can just use std::rotate or std::rotate_copy.
The functions' interfaces are a bit more complex than rotation in your Python example, though. You have to provide, as a second argument, an iterator to the element which will become the first element in the resulting array.
For an array { 1, 2, 3, 4, 5 } and a forward rotation by one element, that would be the second element (the "2"). You get an iterator to that element by adding 1 to an iterator to the array's first element, for example array.begin() + 1, assuming that you use std::array, or array + 1 if it's a raw array.
#include <iostream>
#include <algorithm>
#include <array>
int main()
{
std::array<int, 5> array = { 1, 2, 3, 4, 5 };
std::rotate(
array.begin(),
array.begin() + 1,
array.end()
);
for (auto&& element : array)
{
std::cout << element << "\n";
}
}
If you want an interface like in your Python code, then you can wrap std::rotate in a function of your own and provide an int parameter. This is also a nice opportunity to make the whole thing more reusable by creating a generic function which can be used with any suitable container:
#include <iostream>
#include <algorithm>
#include <array>
#include <vector>
#include <list>
template <class Container>
void rotate(Container& container, int n)
{
using std::begin;
using std::end;
auto new_begin = begin(container);
std::advance(new_begin, n);
std::rotate(
begin(container),
new_begin,
end(container)
);
}
int main()
{
std::array<int, 5> array = { 1, 2, 3, 4, 5 };
rotate(array, 1);
std::vector<int> vector = { 1, 2, 3, 4, 5 };
rotate(vector, 3);
std::list<int> list = { 1, 2, 3, 4, 5 };
rotate(list, 2);
int raw_array[] = { 1, 2, 3, 4, 5 };
rotate(raw_array, 3);
// test output goes here...
}
Note how std::begin and std::end make sure that raw arrays (with their begin + N syntax) and container classes (with their c.begin() + N syntax) are both supported, and std::advance makes the function work for containers with non-random-access iterators like std::list (where you must increment iterators repeatedly to advance them by more than one element).
By the way, if you want to support n arguments greater than or equal to the container's size, then you can use the C++17 function std::size or just create your own. And perhaps use assert to catch accidental negative arguments:
assert(n >= 0);
using std::size;
n = n % size(container);
Related
I want to delete items in vector by indices in cpp code. However it is too slow
cpp version
long remove_cnt = 0;
for (auto &remove_idx : remove_index) {
mylist.erase(mylist.begin() + (long) remove_idx - remove_cnt);
remove_cnt++;
}
python version
new_mylist = [item for i, item in enumerate(mylist) if i not in remove_index]
I expect that cpp is faster than python. But my cpp code is too slower than python code. Are there other efficient code in cpp??
Your question is a good example of why a 1-1 translation between languages usually doesn't work.
To efficiently erase items from a vector you don't do it by index.
Assuming you got your indices in python by evaluating some condition (a predicate). You can directly use this predicate in C++.
Say you want to remove all ints > 4 then the code looks like this:
#include <algorithm>
#include <iostream>
#include <vector>
bool greater_then_4(const int value)
{
return value > 4;
}
int main()
{
std::vector<int> values{ 1, 2, 3, 4, 5, 6, 7, 8 };
// https://en.cppreference.com/w/cpp/algorithm/remove
// remove all values greater then 4. remove will actually move all those values till the end
auto it = std::remove_if(values.begin(), values.end(), greater_then_4);
// shrink the vector to only include the items not matching the predicate
values.erase(it, values.end());
for (const auto value : values)
{
std::cout << value << " ";
}
return 0;
}
Is there a faster way to the following in c++, so that i can outperform the python's implementation?
Get intersection of two map/unordered_map keys
For these intersected keys, compute the pairwise difference between elements of their respective set/unordered_set
Some info that might be useful:
hash_DICT1 has about O(10000)keys, and about O(10) elements in the each set.
hash_DICT2 has about O(1000)keys, and about O(1) elements in the each set.
For example:
map <int,set<int>> hash_DICT1;
hash_DICT1[1] = {1,2,3};
hash_DICT1[2] = {4,5,6};
map <int,set<int>> hash_DICT2;
hash_DICT2[1] = {11,12,13};
hash_DICT2[3] = {4,5,6};
vector<int> output_vector
= GetPairDiff(hash_DICT1, hash_DICT2)
= [11-1,12-1,13-1,
11-2,12-2,13-2,
11-3,12-3,13-3] // only hashkey=1 is intersect, so only compute pairwise difference of the respective set elements.
= [10, 11, 12,
9, 10, 11,
8, 9, 10] // Note that i do want to keep duplicates, if any. Order does not matter.
GetPairDiff function.
vector<int> GetPairDiff(
unordered_map <int, set<int>> &hash_DICT1,
unordered_map <int, set<int>> &hash_DICT2) {
// Init
vector<int> output_vector;
int curr_key;
set<int> curr_set1, curr_set2;
// Get intersection
for (const auto &KEY_SET:hash_DICT2) {
curr_key = KEY_SET.first;
// Find pairwise difference
if (hash_DICT1.count(curr_key) > 0){
curr_set1 = hash_DICT1[curr_key];
curr_set2 = hash_DICT2[curr_key];
for (auto it1=curr_set1.begin(); it1 != curr_set1.end(); ++it1) {
for (auto it2=curr_set2.begin(); it2 != curr_set2.end(); ++it2) {
output_vector.push_back(*it2 - *it1);
}
}
}
}
}
main run
int main (int argc, char ** argv) {
// Using unordered_map
unordered_map <int,set<int>> hash_DICT_1;
hash_DICT_1[1] = {1,2,3};
hash_DICT_1[2] = {4,5,6};
unordered <int,set<int>> hash_DICT_2;
hash_DICT_2[1] = {11,12,13};
hash_DICT_2[3] = {4,5,6};
GetPairDiff(hash_DICT_1, hash_DICT_1);
}
Compiled like this
g++ -o ./CompareRunTime.out -Ofast -Wall -Wextra -std=c++11
Other data structures are welcomed, such as map or unordered_set.
However i did try all 4 permutations, and found the one given by GetPairDiff runs the fastest, but nowhere near as fast as the python's implementation:
hash_DICT1 = { 1 : {1,2,3}, 2 : {4,5,6} }
hash_DICT2 = { 1 : {11,12,13}, 3 : {4,5,6} }
def GetPairDiff(hash_DICT1, hash_DICT2):
vector = []
for element in hash_DICT1.keys() & hash_DICT2.keys():
vector.extend(
[db_t-qry_t
for qry_t in hash_DICT2[element]
for db_t in hash_DICT1[element] ])
return vector
output_vector = GetPairDiff(hash_DICT1, hash_DICT2)
Performance comparison:
python : 0.00824 s
c++ : 0.04286 s
The implementation by c++ takes about 5 times the time taken !!!
You do a lot of copying where you should be using const&.
You don't save search results. You should use find instead of count and then use the result.
push_back to a vector may be made faster by reserve()ing the number of elements you need to store if you know the number in advance.
Fixing these issues could result in something like this (requires C++17):
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using container = std::unordered_map<int, std::unordered_set<int>>;
std::vector<int> GetPairDiff(const container& hash_DICT1,
const container& hash_DICT2) {
// Init
std::vector<int> output_vector;
// Get intersection
for(auto& [curr_key2, curr_set2] : hash_DICT2) {
// use find() instead of count()
if(auto it1 = hash_DICT1.find(curr_key2); it1 != hash_DICT1.end()) {
auto& curr_set1 = it1->second;
// Reserve the space you know you'll need for this iteration. Note:
// This might be a pessimizing optimization so try with and without it.
output_vector.reserve(curr_set1.size() * curr_set2.size() +
output_vector.size());
// Calculate pairwise difference
for(auto& s1v : curr_set1) {
for(auto& s2v : curr_set2) {
output_vector.emplace_back(s2v - s1v);
}
}
}
}
return output_vector;
}
int main() {
container hash_DICT1{{1, {1, 2, 3}},
{2, {4, 5, 6}}};
container hash_DICT2{{1, {11, 12, 13}},
{3, {4, 5, 6}}};
auto result = GetPairDiff(hash_DICT1, hash_DICT2);
for(int v : result) {
std::cout << v << '\n';
}
}
This is more than 8 times as fast as the python version for these containers on my computer compiled with g++ -std=c++17 -O3.
Here's a C++11 version of the same program:
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using container = std::unordered_map<int, std::unordered_set<int>>;
std::vector<int> GetPairDiff(const container& hash_DICT1,
const container& hash_DICT2) {
// Init
std::vector<int> output_vector;
// Get intersection
for(auto& curr_pair2 : hash_DICT2) {
auto& curr_key2 = curr_pair2.first;
auto& curr_set2 = curr_pair2.second;
// use find() instead of count()
auto it1 = hash_DICT1.find(curr_key2);
if(it1 != hash_DICT1.end()) {
auto& curr_set1 = it1->second;
// Reserve the space you know you'll need for this iteration. Note:
// This might be a pessimizing optimization so try with and without it.
output_vector.reserve(curr_set1.size() * curr_set2.size() +
output_vector.size());
// Calculate pairwise difference
for(auto& s1v : curr_set1) {
for(auto& s2v : curr_set2) {
output_vector.emplace_back(s2v - s1v);
}
}
}
}
return output_vector;
}
int main() {
container hash_DICT1{{1, {1, 2, 3}},
{2, {4, 5, 6}}};
container hash_DICT2{{1, {11, 12, 13}},
{3, {4, 5, 6}}};
auto result = GetPairDiff(hash_DICT1, hash_DICT2);
for(int v : result) {
std::cout << v << '\n';
}
}
Can I use pybind1 to pass a three-dimensional numpy array to a c++ function accepting an Eigen::Tensor as argument. For example, consider the following c++ function:
Eigen::Tensor<double, 3> addition_tensor(Eigen::Tensor<double, 3> a,
Eigen::Tensor<double, 3> b) {
return a + b;
}
after compiling the function, importing it to python and passing a the numpy array np.ones((1, 2, 2)) to it, I receive the following error message:
TypeError: addition_tensor(): incompatible function arguments. The following argument types are supported:
1. (arg0: Eigen::Tensor<double, 3, 0, long>, arg1: Eigen::Tensor<double, 3, 0, long>) -> Eigen::Tensor<double, 3, 0, long>
I am in particular surprised about not being able to pass a three dimensional numpy array as I can pass a two dimensional numpy array to a function accepting an Eigen::MatrixXd, as:
Eigen::MatrixXd addition(Eigen::MatrixXd a, Eigen::MatrixXd b) { return a + b; }
The entire code I used for this example is:
#include <eigen-git-mirror/Eigen/Dense>
#include <eigen-git-mirror/unsupported/Eigen/CXX11/Tensor>
#include "pybind11/include/pybind11/eigen.h"
#include "pybind11/include/pybind11/pybind11.h"
Eigen::MatrixXd addition(Eigen::MatrixXd a, Eigen::MatrixXd b) { return a + b; }
Eigen::Tensor<double, 3> addition_tensor(Eigen::Tensor<double, 3> a,
Eigen::Tensor<double, 3> b) {
return a + b;
}
PYBIND11_MODULE(example, m) {
m.def("addition", &addition, "A function which adds two numbers");
m.def("addition_tensor", &addition_tensor,
"A function which adds two numbers");
}
I compiled the code above with g++ -shared -fPIC `python3 -m pybind11 --includes` example.cpp -o example`python3-config --extension-suffix`. Does somebody have an idea how I can a three-dimensional numpy array to a function accepting a three-dimensional Eigen::Tensor?
It is not directly supported, here's some discussion (including some code to do the mapping if you want to add that to your project): https://github.com/pybind/pybind11/issues/1377
Thanks for #John Zwinck's answer, I could achieve what I was looking for. In case somebody is interested, here is the replication:
#include <eigen-git-mirror/Eigen/Dense>
#include <eigen-git-mirror/unsupported/Eigen/CXX11/Tensor>
#include "pybind11/include/pybind11/eigen.h"
#include "pybind11/include/pybind11/numpy.h"
#include "pybind11/include/pybind11/pybind11.h"
Eigen::Tensor<double, 3, Eigen::RowMajor> getTensor(
pybind11::array_t<double> inArray) {
// request a buffer descriptor from Python
pybind11::buffer_info buffer_info = inArray.request();
// extract data an shape of input array
double *data = static_cast<double *>(buffer_info.ptr);
std::vector<ssize_t> shape = buffer_info.shape;
// wrap ndarray in Eigen::Map:
// the second template argument is the rank of the tensor and has to be
// known at compile time
Eigen::TensorMap<Eigen::Tensor<double, 3, Eigen::RowMajor>> in_tensor(
data, shape[0], shape[1], shape[2]);
return in_tensor;
}
pybind11::array_t<double> return_array(
Eigen::Tensor<double, 3, Eigen::RowMajor> inp) {
std::vector<ssize_t> shape(3);
shape[0] = inp.dimension(0);
shape[1] = inp.dimension(1);
shape[2] = inp.dimension(2);
return pybind11::array_t<double>(
shape, // shape
{shape[1] * shape[2] * sizeof(double), shape[2] * sizeof(double),
sizeof(double)}, // strides
inp.data()); // data pointer
}
pybind11::array_t<double> addition(pybind11::array_t<double> a,
pybind11::array_t<double> b) {
Eigen::Tensor<double, 3, Eigen::RowMajor> a_t = getTensor(a);
Eigen::Tensor<double, 3, Eigen::RowMajor> b_t = getTensor(b);
Eigen::Tensor<double, 3, Eigen::RowMajor> res = a_t + b_t;
return return_array(res);
}
PYBIND11_MODULE(example, m) {
m.def("addition", &addition, "A function which adds two numbers");
}
In contrast to the suggestion in the link John referred to, I didn't mind using RowMajor storage order for Eigen::Tensor. I saw this storage order being used several times in the tensorflow code too. I do not know if the code above unnecessarily copies data though.
I want to implement insert in C++ like this:
// python code
insertIndexes = [1, 1, 2, 2, 3, 3, 5]
arr = []
toInsertValue = 0;
for i in insertIndexes:
arr.insert(i, toInsertValue)
toInsertValue += 1
print arr // [0, 1, 3, 5, 4, 6, 2]
but I find that I have to know vector size if I want to use insert in C++:
// !!C++ wrong code!!
// vec is not initialized correctly
vector<int> vec;
int insertIndexes[] = {1, 1, 2, 2, 3, 3, 5}
int toInsertValue = 0;
for (int i = 0; i < sizeof(insertIndexes)/sizeof(insertIndexes[0]); i++) {
vec.insert(vec.begin() + insertIndexes[i], toInsertValue);
toInsertValue += 1;
}
In Python, inserting at an index outside the list size is very forgiving, the implementation checks that the insert location is greater than or equal to len(list), then the new item is inserted appended. In C++'s std::vector, this is not so. You will have to make that check yourself.
auto offset = 0;
for(auto x : indexes){
if(x < vec.size()) //Is the selected index in range?
vec.insert(vec.begin() + x, offset++);
else
vec.insert(vec.end(), offset++);
}
Full example:
std::vector<int> indexes = {1, 1, 2, 2, 3, 3, 5};
std::vector<int> vec;
auto offset = 0;
for(auto x : indexes){
auto iter = (x < int(vec.size())) ? vec.begin() + x : vec.end();
vec.insert(iter, offset++);
}
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));
Outputs (As seen Live On Coliru ):
0 1 3 5 4 6 2
When you define a vector without a specific size, it will be empty and all indexing into it (with or without iterators) will be out of bounds leading to undefined behavior.
In your loop you need to check that indexes[i] will not be out of bounds, and if it is then resize the vector appropriately or use push_back to append the value offset to the vector.
If there is no equivalent function; is it possible to cleanly generate a QList<int> of (1, 2, 3, 4, 5 ... ) with one line of code, avoiding a for loop or having to write my own function?
I don't know the particularities of Qt containers, but in the STL you could do something like:
std::vector<int> v(n);
std::iota(v.begin(), v.end(), 1);
Or, if not using C++11, std::generate_n(v.begin(), v.end(), my_iota(1)); where my_iota is a functor written by you that simply returns n++, with the initial value of n provided in the ctor.
If Qt containers provide iterators that comply with the STL OutputIterator concept you should be OK using std::generate or std::iota.
Qt containers (QList and QVector) provide STL compatible iterators that can utilize this functionality:
#include <QDebug>
#include <QVector>
#include <numeric>
inline QVector<int> range(int start, int end)
{
QVector<int> l(end-start+1);
std::iota(l.begin(), l.end(), start);
return l;
}
int main()
{
qDebug() << range(-3, 4);
return 0;
}
prints
QVector(-3, -2, -1, 0, 1, 2, 3, 4)