I'm just going to come out and ask. I have 500 arrays[127]. I need to sort them all by the value of the very last element in descending order. How would you do this in the most efficient way possible?
EXAMPLE:
float arr1[] = {3,1,4,5};
float arr2[] = {1,2,5,8};
float arr3[] = {102,4,132,2};
OUTPUT:
{arr2,
arr1,
arr3}
Your could create a lightweight wrapper that just stores the begin and end iterators of an array.
#include <iterator>
template<class T>
struct span {
template<size_t N>
span(T (&arr)[N]) : m_begin(std::begin(arr)), m_end(std::end(arr)) {}
T* begin() const { return m_begin; }
T* end() const { return m_end; }
T& front() const { return *m_begin; }
T& back() const { return *std::prev(m_end); }
private:
T* m_begin;
T* m_end;
};
You could then put these lightweight wrappers in a std::vector<span<int>> and sort that. Note that this will not affect the original arrays in any way and since sorting the vector only moves the spans around and not the actual array data, it should be reasonably fast.
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
int arr1[] = {3,1,4,5};
int arr2[] = {1,2,5,8};
int arr3[] = {102,4,132,2};
std::vector<span<int>> arrs{
arr1, arr2, arr3
};
// sort on the last element, decending:
std::sort(arrs.begin(), arrs.end(),[](const auto& lhs, const auto& rhs) {
return rhs.back() < lhs.back();
});
for(auto& arr : arrs) {
for(auto v : arr) std::cout << v << ' ';
std::cout << '\n';
}
}
Output:
1 2 5 8
3 1 4 5
102 4 132 2
Since a raw array is a pointer without size information carried out, your job isn't automatic.
Either you convert all your arrays to std::vector<float> so you can have the last element and then have a std::vector<std::vector<float>> with a custom sort operator to test, or you create a structure that contains the raw array along with size information.
std::vector<float> arr1 = {3,1,4,5}
std::vector<float> arr2 = {1,2,5,8};
std::vector<float> arr3 = {102,4,132,2};
std::vector<std::vector<float>> arrays = {arr1,arr2,arr3};
std::sort(arrays.begin(),arrays.end(),[](const std::vector<float>& r1,const std::vector<float>& r2) -> bool
{
if (r1[r1.size() - 1] < r2[r2.size() - 1]) return true;
return false;
});
struct ArrAndSize { float* arr; size_t sz; };
ArrAndSize arr1 = {{3,1,4,5},4};
ArrAndSize arr2 = {{1,2,5,8},4};
ArrAndSize arr3 = {{102,4,132,2},4};
std::vector<ArrAndSize> arrays = {arr1,arr2,arr3};
std::sort(arrays.begin(),arrays.end(),[](const ArrAndSize& r1,const ArrAndSize& r2) -> bool
{
if (r1.arr[r1.sz - 1] < r2.arr[r2.sz - 1]) return true;
return false;
});
In both cases, check if the array has size 0.
Related
I want to create a combination of K elements one each from K sets. Each set can have n elements in it.
set1 = {a1, a2, a3}
set2 = {b1, b2, b3 , b4}
set3 = {c1, c2}
Required Combinations = {{a1,b1,c1}, {a1,b2,c1} ... {a3,b4,c2}}
Number of combinations = 3*4*2 =24
So if K is large and n is large we run into Out of Memory very quickly. Refer to the below code snippet how we are creating combinations today. If we create all the combinations in a case where K is relatively large, we go out of memory! So for instance, if K=20 and each set has 5 elements, the combinations are 5^20, which is extremely large in memory. So I want an alternative algorithm where I don't need to store all those combinations in memory all at a time before I start consuming the combinations.
vector<vector<string>> setsToCombine;
vector<vector<string>> allCombinations;
vector<vector<string>> *current =
new vector<vector<string>>{vector<string>()};
vector<vector<string>> *next = new vector<vector<string>>();
vector<vector<string>> *temp;
for (const auto& oneSet : setsToCombine) {
for (auto& cur : *current) {
for (auto& oneEle : oneSet) {
cur.push_back(oneEle);
next->push_back(cur);
cur.pop_back();
}
}
temp = current;
current = next;
next = temp;
next->clear();
}
for (const auto& cur : *current) {
allCombinations.push_back(cur);
}
current->clear();
next->clear();
delete current;
delete next;
You can store the indexes and lazely iterate over the combinations
#include <cstdint>
#include <iostream>
#include <vector>
using v_size_type = std::vector<int>::size_type;
using vv_size_type = std::vector<v_size_type>::size_type;
bool increment(std::vector<v_size_type> &counters, std::vector<v_size_type> &ranges) {
for (auto idx = counters.size(); idx > 0; --idx) {
++counters[idx - 1];
if (counters[idx - 1] == ranges[idx - 1]) counters[idx - 1] = 0;
else return true;
}
return false;
}
std::vector<int> get(const std::vector<std::vector<int>> &sets, const std::vector<v_size_type> &counters) {
std::vector<int> result(sets.size());
for (vv_size_type idx = 0; idx < counters.size(); ++idx) {
result[idx] = sets[idx][counters[idx]];
}
return result;
}
void print(const std::vector<int> &result) {
for (const auto el : result) {
std::cout << el << ' ';
}
}
int main() {
const std::vector<std::vector<int>> sets = {{-5, 2}, {-100, -21, 0, 15, 32}, {1, 2, 3}};
std::vector<v_size_type> ranges(sets.size());
for (vv_size_type idx = 0; idx < sets.size(); ++idx) {
ranges[idx] = sets[idx].size();
}
std::vector<v_size_type> counters(sets.size());
while (true) {
print(get(sets, counters));
std::cout << '\n';
if (!increment(counters, ranges)) break;
}
}
Godbolt
You can also use the odometer approach.
First, let us look again, what an odometer is. It looks like this:
There are several disks, with values printed on it. And if the odometer runs forward, it will show the Cartesian product of all values on the disks.
That is somehow clear, but how to use this principle? The solution is, that each set of values will be a disk, and the values of the set, will be put on the corresponding disk. With that, we will have an odometer, where the number of values on each disk is different. But this does not matter.
Also here, if a disks overflows, the next disk is incremented. Same principle like a standard odometer. Just with maybe more or less values.
And, you can put everything on a disk, not just integers. This approach will work always.
We can abstract a disk as a std::vector of your desired type. And the odometer is a std::vector of disks.
All this we can design in a class. And if we add iterator functionality to the class, we can easily handle it.
In the example below, I show only a minimum set of functions. You can add as many useful functions to this class as you like and tailor it to your needs.
The object oriented approach is often better to understand in the end.
Please check:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <initializer_list>
#include <algorithm>
#include <iterator>
using MyType = int;
using Disk = std::vector<MyType>;
using Disks = std::vector<Disk>;
// Abstraction for a very simple odometer
class Odometer {
Disks disks{};
public:
// We will do nearly everything with the iterator of the odometer class
struct iterator {
// Definitions for iterator ----------------
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = std::vector<MyType>;
using pointer = std::vector<MyType>*;
using reference = std::vector<MyType>&;
const Disks& d; // Reference to disks from super class
int overflow{}; // Indicates an overflow of all disks
std::vector<std::size_t>positions{}; // Stores position of any disks
// Iterator constructor
iterator(const Disks& dd, const int over = 0) : d(dd), overflow(over) {
positions = std::vector<std::size_t>(dd.size(), 0);
}
// Dereference iterator
value_type operator*() const {
std::vector<MyType> result(d.size());
for (std::size_t i{}; i < d.size(); ++i) result[i] = d[i][positions[i]];
return result;
};
// Comparison
bool operator != (const iterator& other) { return positions != other.positions or overflow != other.overflow; }
// And increment the iterator
iterator operator++() {
int carry = 0; std::size_t i{};
for (i=0; i < d.size(); ++i) {
if (positions[i] >= d[i].size() - 1) {
positions[i] = 0;
carry = 1;
}
else {
++positions[i];
carry = 0;
break;
}
}
overflow = (i == d.size() and carry) ? 1 : 0;
return *this;
}
};
// Begin and End functions. End is true, if there is a flip over of all disks
iterator begin() const { return iterator(disks); }
iterator end() const { return iterator(disks, 1); }
// Constructors
Odometer() {}; // Default (useless for this example)
// Construct from 2d initializer list
Odometer(const std::initializer_list<const std::initializer_list<MyType>> iil) {
for (const std::initializer_list<MyType>& il : iil) {
disks.push_back(il);
}
}
// Variadic. Parameter pack and fold expression
template <typename ... Args>
Odometer(Args&&... args) {
(disks.push_back(std::forward<Args>(args)), ...);
}
// Simple output of everything
friend std::ostream& operator << (std::ostream& os, const Odometer& o) {
for (const auto vi : o) {
for (const MyType i : vi) os << i << ' ';
os << '\n';
}
return os;
}
};
// Some test
int main() {
// Define Odometer. Initialiaze wit normal initializer list
Odometer odo1{ {1,2},{3},{4,5,6} };
// Show complete output
std::cout << odo1 << "\n\n\n";
// Create additional 3 vectors for building a new cartesian product
std::vector<MyType> v1{ 1,2 };
std::vector<MyType> v2{ 3,4 };
std::vector<MyType> v3{ 5,6 };
// Define next Odometer and initialize with variadic constructor
Odometer odo2(v1, v2, v3);
// Use range based for loop for output
for (const std::vector<MyType>& vm : odo2) {
for (const MyType i : vm) std::cout << i << ' ';
std::cout << '\n';
}
}
is there a way to declare a range based array in c++ arduino for example instad of writing
const int array[] = {2,3,4,5,6};
why isn't it possible to declare an array like this?
const int array[] = {2:6};
I assume that you are not using the Arduino STL, so you could create a simple array wrapping class template, similar to std::array, that takes two template parameters: The type, T, and the size, N.
Example:
template<class T, size_t N>
struct array {
// misc typedef's:
using value_type = T;
using const_pointer = const value_type*;
using pointer = value_type*;
using const_iterator = const value_type*;
using iterator = value_type*;
size_t size() const { return N; } // the fixed size of the array
// subscripting:
const T& operator[](size_t idx) const { return data[idx]; }
T& operator[](size_t idx) { return data[idx]; }
// implicit conversions when passed to functions:
operator const_pointer () const { return data; }
operator pointer () { return data; }
// iterator support:
const_iterator cbegin() const { return data; }
const_iterator cend() const { return data + N; }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
iterator begin() { return data; }
iterator end() { return data + N; }
T data[N]; // the actual array
};
You could then create a small helper function to create arrays and fill them with a range of values like in your question:
template<class T, T min, T max>
array<T, max - min + 1> make_array_min_max() {
array<T, max - min + 1> rv;
for(T i = min; i <= max; ++i) rv[i - min] = i;
return rv;
}
The creation would just be slightly different, but you could then use it pretty much like you use a normal array.
void func(const int* a, size_t s) { // C-style interface
for(size_t i = 0; i < s; ++i)
std::cout << a[i] << ' ';
std::cout << '\n';
}
int main() {
const auto arr = make_array_min_max<int, 2, 6>(); // create the range you want
func(arr, arr.size()); // implicit conversion to `const int*` for `arr`
for(auto v : arr) // range-based for loop
std::cout << v << ' ';
std::cout << '\n';
for(size_t i = 0; i < arr.size(); ++i) // classing loop
std::cout << arr[i] << ' ';
std::cout << '\n';
}
Output:
2 3 4 5 6
2 3 4 5 6
2 3 4 5 6
I have a 2d array in which the columns'size length is not the same. So how to loop all elements in that 2d array dynamically?
string** arr = new string*[4];
arr[0] = new string[5];
arr[1] = new string[3];
arr[2] = new string[4];
arr[3] = new string[2];
Using dynamic arrays like that becomes harder to maintain and doesn't really give you any benefits over using a std::vector. You would need to store the size of each array separately.
Example:
#include <iterator>
#include <memory>
#include <utility>
template<typename T>
struct myarr {
myarr() = default;
myarr(size_t size) : arr(std::make_unique<T[]>(size)), m_size(size) {}
T& operator[](size_t idx) { return arr[idx]; }
const T& operator[](size_t idx) const { return arr[idx]; }
auto cbegin() const { return &arr[0]; }
auto cend() const { return std::next(cbegin(), m_size); }
auto begin() const { return cbegin(); }
auto end() const { return cend(); }
auto begin() { return &arr[0]; }
auto end() { return std::next(begin(), m_size); }
private:
std::unique_ptr<T[]> arr;
size_t m_size;
};
int main() {
myarr<myarr<std::string>> arr(4);
arr[0] = myarr<std::string>(5);
arr[1] = myarr<std::string>(3);
arr[2] = myarr<std::string>(4);
arr[3] = myarr<std::string>(2);
for(auto& inner : arr) {
for(const std::string& str : inner) {
// do stuff
}
}
}
The std::vector-based code would only require the below and offers far more flexibility:
Example:
std::vector<std::vector<std::string>> arr(4);
arr[0].resize(5);
arr[1].resize(3);
arr[2].resize(4);
arr[3].resize(2);
I've been thinking if it is possible to actually let the user decide how many "dimensions" an array should have, based on a number given.
Let n be the number of dimensions, the user will type in its value.
It will create an array with n dimensions.
Example: for n=5, it will create an array called list, like that: int list[size1][size2][size3][size4][size5].
size variables will still be mentioned by the user, but that's actually part 2.
I want to know if I can add more dimensions to an array, after I have declared it. And if not, I want to find a solution to this problem.
The C++ language does not have provision for variable-sized or variable-dimensioned arrays.
You can, however, create a class to encapsulate these behaviors.
The important characteristic is the dimensions. You can use a std::vector<int> to track the number of elements per dimension; for example, {3, 4, 5} to represent a three-dimensional matrix where the rank of the innermost dimension is 3, the middle 4, and the outer 5.
Use a templated vector or deque to allocate space for the elements. The number of elements required is the product of the dimension ranks. (You can use std::accumulate with a multiplication operator to compute this over your ranks vector.)
Next, you'll need a method that takes some object (say, a vector of int) that provides all the indices into the MD-array necessary to access an element. You can provide overloads that take a variable number of arguments using some fancy template metaprogramming.
All of this is overkill outside of some very specialized uses, such as: you are writing Mathematica-like software that allows users to play with these things.
You may be interested in an array class I implemented a few months ago that aims to provide a syntax for arrays that mimics that of matlab arrays. It utilizes initilizer_list syntax to allow for arbitrary dimensional arrays to be created using
Array<double> array({10, 20, 30});
You can then access and modify individual elements using
double d = array[{1, 2, 3}];
array[{1, 2, 3}] = 10;
And even slice the matrix up into pieces using
array.getSlice({___, 3, 4});
where "___" is used as a wildcard.
See more on: http://www.second-quantization.com/Array.html
Implementation: https://github.com/dafer45/TBTK/blob/master/Lib/include/Utilities/TBTK/Array.h
Solution for object let's the user choose the number of dimensions. A little robust, my C++ maybe is not the best, but it was fun implementing. nvector<T> represents resizable (in dimensions and count of elements in each dimension) array of element of T type, although only some resize functions are implemented. narray<T> is the same, but the number of dimensions is not resizable. This works around the idea of recalculating index position of a multidimensional array using a single continuous array.
#include <cstdio>
#include <vector>
#include <iostream>
#include <cstddef>
#include <cstdarg>
#include <algorithm>
#include <numeric>
#include <cassert>
#include <memory>
#include <cstring>
using namespace std;
template<typename T>
class narray {
public:
static size_t compute_size(initializer_list<size_t>& dims) {
return accumulate(dims.begin(), dims.end(), 1, multiplies<size_t>());
}
static size_t compute_size(vector<size_t>& dims) {
return accumulate(dims.begin(), dims.end(), 1, multiplies<size_t>());
}
static size_t compute_distance(vector<size_t>& dims) {
return dims.size() > 1 ? dims[1] : 1;
}
static vector<size_t> remove_one_dim(vector<size_t> dims_) {
return vector<size_t>(dims_.begin() + 1, dims_.end());
}
narray(initializer_list<size_t> dims, T* data) :
dims_(dims), data_(data) {}
narray(vector<size_t> dims, T* data) :
dims_(dims), data_(data) {}
T operator*() {
return *data_;
}
T* operator&() {
return data_;
}
void operator=(T v) {
if (dims_.size() != 0)
throw runtime_error(__PRETTY_FUNCTION__);
*data_ = v;
}
void operator=(initializer_list<T> v) {
if (v.size() > size())
throw runtime_error(__PRETTY_FUNCTION__);
copy(v.begin(), v.end(), data_);
}
T* data() {
return data_;
}
T* data_last() {
return &data()[compute_size(dims_)];
}
size_t size() {
return compute_size(dims_);
}
size_t size(size_t idx) {
return dims_[idx];
}
narray<T> operator[](size_t idx) {
if (dims_.size() == 0)
throw runtime_error(__PRETTY_FUNCTION__);
return narray<T>(remove_one_dim(dims_),
&data_[idx * compute_distance(dims_)]);
}
class iterator {
public:
iterator(initializer_list<size_t>& dims, T* data) :
dims_(dims), data_(data) { }
iterator(vector<size_t>& dims, T* data) :
dims_(dims), data_(data) { }
iterator operator++() {
iterator i = *this;
data_ += compute_distance(dims_);
return i;
}
narray<T> operator*() {
return narray<T>(remove_one_dim(dims_), data_);
}
bool operator!=(const iterator& rhs) {
if (dims_ != rhs.dims_)
throw runtime_error(__PRETTY_FUNCTION__);
return data_ != rhs.data_;
}
private:
vector<size_t> dims_;
T* data_;
};
iterator begin() {
return iterator(dims_, data());
}
iterator end() {
return iterator(dims_, data_last());
}
private:
vector<size_t> dims_;
T* data_;
};
template<typename T>
class nvector {
public:
nvector(initializer_list<size_t> dims) :
dims_(dims), data_(narray<T>::compute_size(dims)) {}
nvector(vector<size_t> dims) :
dims_(dims), data_(narray<T>::compute_size(dims)) {}
nvector(initializer_list<size_t> dims, T* data) :
dims_(dims), data_(data) {}
nvector(vector<size_t> dims, T* data) :
dims_(dims), data_(data) {}
T* data() {
return data_.data();
}
T* data_last() {
return &data()[narray<T>::compute_size(dims_)];
}
size_t size() {
return narray<T>::compute_size(dims_);
}
narray<T> operator&() {
return narray<T>(dims_, data());
}
narray<T> operator[](size_t idx) {
if (dims_.size() == 0)
throw runtime_error(__PRETTY_FUNCTION__);
return narray<T>(narray<T>::remove_one_dim(dims_),
&data()[idx * narray<T>::compute_distance(dims_)]);
}
void operator=(initializer_list<T> v) {
if (v.size() > size())
throw runtime_error(__PRETTY_FUNCTION__);
copy(v.begin(), v.end(), data_.begin());
}
auto begin() {
return typename narray<T>::iterator(dims_, data());
}
auto end() {
return typename narray<T>::iterator(dims_, data_last());
}
// add and remove dimensions
void dimension_push_back(size_t dimsize) {
dims_.push_back(dimsize);
data_.resize(size());
}
void dimension_pop_back() {
dims_.pop_back();
data_.resize(size());
}
// TODO: resize dimension of index idx?
private:
vector<size_t> dims_;
vector<T> data_;
};
int main()
{
nvector<int> A({2, 3});
A = { 1,2,3, 4,5,6 };
assert(A.size() == 6);
assert(&A[0] == &A.data()[0]);
assert(&A[0][0] == &A.data()[0]);
assert(&A[1] == &A.data()[3]);
assert(&A[0][1] == &A.data()[1]);
assert(&A[1][1] == &A.data()[4]);
cout << "Currently array has " << A.size() << " elements: " << endl;
for(narray<int> arr1 : A) { // we iterate over arrays/dimensions
for(narray<int> arr2 : arr1) { // the last array has no dimensions
cout << "elem: " << *arr2 << endl;
}
}
cout << endl;
// assigment example
cout << "Now it is 4: " << *A[1][0] << endl;
A[1][0] = 10;
cout << "Now it is 10: " << *A[1][0] << endl;
return 0;
}
This code needs still much more work. It works only as a simple example. Maybe use shared_ptr in narray? Implement better exceptions?
So creating an array of n=5 dimensions with sizes size1, size2, size3, size4 and size5 would like this:
narray<int> arr({size1, size2, size3, size4, size5});
arr[0][1][2][3][4] = 5; // yay!
I have a vector of vectors, representing an array. I would like to remove rows efficiently, ie with minimal complexity and allocations
I have thought about building a new vector of vectors, copying only non-deleted rows, using move semantics, like this:
//std::vector<std::vector<T> > values is the array to remove rows from
//std::vector<bool> toBeDeleted contains "marked for deletion" flags for each row
//Count the new number of remaining rows
unsigned int newNumRows = 0;
for(unsigned int i=0;i<numRows();i++)
{
if(!toBeDeleted[i])
{
newNumRows++;
}
}
//Create a new array already sized in rows
std::vector<std::vector<T> > newValues(newNumRows);
//Move rows
for(unsigned int i=0;i<numRows();i++)
{
if(!toBeDeleted[i])
{
newValues[i] = std::move(values[i]);
}
}
//Set the new array and clear the old one efficiently
values = std::move(newValues);
Is this the most effective way?
Edit : I just figured that I could avoid allocating a new array by moving rows down iteratively, this could be slightly more efficient and code is much more simple:
unsigned int newIndex = 0;
for(unsigned int oldIndex=0;oldIndex<values.size();oldIndex++)
{
if(!toBeDeleted[oldIndex])
{
if(oldIndex!=newIndex)
{
values[newIndex] = std::move(values[oldIndex]);
}
newIndex++;
}
}
values.resize(newIndex);
Thanks!
This can be solved using a variation on the usual erase-remove idiom, with a lambda inside the std::remove_if that looks up the index of the current row inside an iterator range of to be removed indices:
#include <algorithm> // find, remove_if
#include <iostream>
#include <vector>
template<class T>
using M = std::vector<std::vector<T>>; // matrix
template<class T>
std::ostream& operator<<(std::ostream& os, M<T> const& m)
{
for (auto const& row : m) {
for (auto const& elem : row)
os << elem << " ";
os << "\n";
}
return os;
}
template<class T, class IdxIt>
void erase_rows(M<T>& m, IdxIt first, IdxIt last)
{
m.erase(
std::remove_if(
begin(m), end(m), [&](auto& row) {
auto const row_idx = &row - &m[0];
return std::find(first, last, row_idx) != last;
}),
end(m)
);
}
int main()
{
auto m = M<int> { { 0, 1, 2, 3 }, { 3, 4, 5, 6 }, { 6, 7, 8, 9 }, { 1, 0, 1, 0 } };
std::cout << m << "\n";
auto drop = { 1, 3 };
erase_rows(m, begin(drop), end(drop));
std::cout << m << "\n";
}
Live Example.
Note: because from C++11 onwards, std::vector has move semantics, shuffling rows around in your std::vector<std::vector<T>> is done using simple pointer manipulations, regardless of your type T (it would be quite different if you want column-deletion, though!).