How to Implement a multidimensional array if the dimension is unknown at compile-time? - c++

I want to implement a function that gets as a parameter a dimension "n" of an array of integers. This function also gets values "k_1, k_2, ..., k_n" defining the size of the array. Then this function will fill this n-dimensional array.
How do I implement this efficiently with C++?
For example for n = 3 I would use
vector < vector < vector < int > > > array;
But I don't know the dimension at compile time.

Use a one-dimensional array, and fake the other dimensions using multiplication of offsets for indexing, and you can pass the dimension sizes in by vector, i.e.
std::vector<int> create_md_array(const std::vector<int> & dimensions)
{
int size = std::accumulate(dimensions.begin(), dimensions.end(), 1, std::multiplies<int>());
return std::vector<int>(size);
}

You have a couple of choices. You can implement it yourself, basically multiplying the coordinates by the sizes to linearize the multi-dimensional address, and just have a simple std::vector<whatever> to hold the data.
Alternatively, you could use std::valarray and friends to accomplish the same. It has a set of classes that are specifically intended for the kind of situation you describe -- but they're used so rarely that almost nobody understands them. Writing the code yourself stands a good chance of being easier for most people to read and understand.

Related

create a Dynamic std::array of std::array

My task requires me to create an array of arrays to store some data , where the number of row is fixed and the columns are to be decided at run-time.
If I was using a simple int array then this would've been a simple task but because I have to use std::array , I am lost .
My attempt so far
#include<iostream>
#include<array>
using std::array;
int main(){
array<array<int,1>*,3> x;
for(size_t i=0;i<3;i++)
{
x[i][0]=array<int,3>;
}
}
which leads to the error
array1.cpp:12:29: error: expected '(' for function-style cast or type
construction
x[i][0]=array;
~~~~~~~~~~~~^ 1 error generated.
when using clang++
I have read that an std::array is equivalent to a normal array ,
I know i can use vectors but since i know how many rows i have from the beginning , I feel it to be a waste to use vectors , while I would love the added functionality of std::array when compared to a traditional array. How do I implement this .
std::array<std::vector<int>,3> is the type you want.
std::vector is a dynamicly sized array.
int main(){
std::array<std::vector<int>,3> x;
for(std::size_t i=0;i<3;i++)
{
x[i]=std::vector<int>(22);
}
}
this creates a 3 "major" element array of 22 "minor" size.
Note that column-major and row-major (which is first and which is second) is a matter of convention. So std::vector<std::array<3,int>> is another equally valid interpretation of the requirements.
If you are banned from using std::vector, you will have to figure out an alternative solution, possibly rolling your own. I'd advise against unique_ptr<int[]> (or worse, raw pointers) as they don't store the size of the element.
A std::array< std::array< cannnot be dynamic in either dimension. std::array is fixed size.
My task requires me to create an array of arrays to store some data , where the number of row is fixed and the columns are to be decided at run-time.
It sounds like your task requires using a matrix class. Like boost::numeric::ublas::matrix.
The benefit of using a matrix class is that internally it uses one dynamic array to minimize storage overhead.
If you are coding this as an exercise create your own matrix class. Otherwise use an existing one.

Dynamic allocated 2d array

I have in my class 2 const int variables:
const int m_width;
const int m_height;
In my constructor, I have set the variables and I want to create a 2D array with exactly this size that will be passed by value from the player. I am trying to make a TicTacToe game. I need the input of the user to determine the size of the playing field(in this case the width and height of it). How do I dynamically declare a 2D array in my situation?
It is a common misconception that 2-dimensional matrices should be supported by two-dimensional storage. People often try to use vectors of vectors or other techniques, and this comes at a cost, both performance and code maintainability.
This is not needed. In fact, perfect two-dimensional matrix is a single std::vector, where every row is packed one after each another. Such a vector has a size of of M * N, where M and N are matrix height and width. To access the element at location X, Y, you do v[K], where K is calculated as X * N + Y.
C++ doesn't provide a standard dynamic 2D array container.
What you can do (if you don't want to write your own full implementation) is use an std::vector of std::vectors instead.
It's not exactly the same thing (provides you with an extra degree of freedom: rows can be of different length) but unless you're working in an extremely constrained environment (or need an extremely optimized solution) the extra cost is not big.
Supposing your elements needs to be integers the code to initialize a 2d array can be for example:
std::vector<std::vector<int>> board(rows, std::vector<int>(cols));
PS: A few years ago I wrote a class here to implement a simple 2D array as an answer to an SO question... you can find it here.

Isolate a column of a vector in c++

I have a 2d vector of string and need to isolate out three of the columns into 3 separate 1d arrays so i can convert them to doubles and perform operations on them.
Simply using:
for (int i = 0; i < 100; i++)
{
vectorname[i][2] = arrayname[i];
}
doesn't work and I don't understand why.
Sorry im new to coding and thanks in advance.
Thanks to first reply, i don't care if i remove the data or not, i just need it so i can operate on it, my vectors are declared as:
string vectorname[101][5];
string arrayname[99];
string arrayname2[99];
string arrayname3[99];
Ok I dont have my vectorname defined as a vector, it's just a 2d string, can i extract a column from that?
Do the columns still need to remain in the 2D vector, or be pulled out completely as independent data?
If you need independent data, I would do
vector<double> col(vectorname[i]);
Then manipulate col as needed. You could even do move construction if you don't need that data in the 2D vector anymore.
I think you have actual logic problems elsewhere though. Show us your vector declarations.
EDIT: What...? You're not declaring vectors at all. You're using pure arrays. And a 2D array shouldn't be called a vector. You're confusing other programmers with your name scheme.
The proper way to declare a vector of strings is
std::vector<string> vectorname(100);
And a vector of vector of strings (a 2D vector) is
std::vector<std::vector<string>(5)> vectorname(101);
But moreover, your dimensions mismatch. Your 1D vectors need to be the same length as the given dimension of your 2D, or 5 (101?) in this case.
If you're trying to copy the values along the first dimension of values, there's no direct constructor for that. You have to manually loop from 0 to 100 and say
arrayname[i] = vectorname[i][n];
Where n is your column number.

Code executing : How to create a multiple dimensional array manually?

If I manually type this script and call the calculator :
integer array[100];
Then my calculator will create a vector<int> object with the name "array" contains 100 elements.
But C++ code is unique. For example if I type and call :
integer array[100][100];
integer array[100][100][100];
//etc
Then the template vector<int> is illegal.... :(
So annoying! I tried but I could not find the better solution. Could anyone give me some hint?
This answer covers to generally different approaches.
To support arbitrarily nested, dynamically sized arrays (so the depth of the nested arrays is not limited during compile time), you should use something like the following.
The type of a variable in your scripting language should be either:
integer
float
(... other primitive types you want to support ...)
an array of any of these types (including array)
(... other container types such as an associative map if you want to support it ...)
This is typically done using a "variant" type, such as Boost Variant or QVariant in Qt. A variant type is basically a union of a set of types (so it is one of them) plus a type descriptor which tells which type it actually contains.
So an array of any type can be represented, also if this "any type" is an array again. So you can support a dynamic depth of nested arrays.
Note that the "array of any types" should actually be a vector of this variant type. The problem with Boost Variant is that you have to explicitly list the types it can hold as template arguments. This will result in a recursion:
boost::variant<int, float, ..., std::vector<boost::variant<..., ...> > >
^^^^^^^^^^^^^^^^^^^^^^^^
recursion
In Qt there is the type QVariant which can hold basically any type supported by Qt. QVariant is not a template class and thus its type doesn't contain such a recursion. I don't know if there is a comparable boost type, but I doubt it.
If your arrays can't be resized during execution of the script (or if they should be resized, you can allocate a new one and copy the contents), there is a simpler solution. Just store the arrays in a one-dimensional vector, also store the dimensions of the array in your scripting language in another vector. Then you can use an index method like the following.
class ScriptArray {
vector<int> dim;
vector<int> elements;
int getIndex(vector<int> indexList) const {
int multiplicator = 1;
int index = 0;
for (int i = 0; i < dim.size(); ++i) {
index = multiplicator * indexList[i];
multiplicator *= dim[i];
}
return index;
}
};
This is basically a generalization of the following idea. Consider a two-dimensional array (100 x 100 elements) you want to represent as a one-dimensional one (10000 elements). For any index in the original array (x, y) you can map this to a one-dimensional index for your internal array (x + 100 * y). For a three-dimensional array this just contains another multiplication (x + 100 * y + 100*100 * z) and so on...
The problem with this solution and resizing the array is that the elements "move" within the array when the size of a dimension changes (special case: last dimension, as this dimension is the "outermost" one). So either you can live with the fact that the array would be invalid when resized, or you copy the contents in a new array with the new size, or you implement some complicated resize method which carefully inserts spaces / removes some elements in the array at the correct places.
I am assuming that you have created your own language that you want to parse using C++. Your parser knows that you are defining a variable, since it finds the type integer before an identifier. What you then have to do is check if you have to create a normal variable or a multi-dimensional array.
If no brackets ([]) exist -> Normal variable
If brackets exist -> Make a loop to count how many there are. Then allocate nested
vectors. Only the final vector will have elements of type int.
So the easiest way to implement this is to forget about an array and just view it as a special case of a multi-dimensional array with only one bracket.

Efficient / elegant two dimensional container

Need for two dimensional array of objects that could be something like:
myContainer<myObject*> *a = new myArray<myObject*>( 20, 20 ); // passing int's as width & height
later accessing values would be done with methods such as:
mylist<myObject*> getRow( int );
mylist<myObject*> getColumn( int );
mylist<myObject*> getDiagonalRow( int );
implementations of those could be something like:
myList<myObject*> myContainer::getRow( int a ){
if( a < 0 && a>=this->height )
return;
myList<myObject*> hlp;
for( int i=0; i<this->width; i++)
hlp.append( this->arr[a][i] );
return hlp; // returns a copy. Could also be a pointer if created with new.
}
Other methods could follow similar lines, ie. creating a list object and filling it with what was requested.
My questions: Can anyone think of elegant way to create a container class I'm describing here. Which could for example avoid creating and filling of list-objects but still maintaining the abstraction and/or usability. Or please advice if I have missed something in STL etc. that has something like this.
STL has the valarray container which can be viewed as row and columns using slices, but you have to do it manually or wrap it into a wrapper class. Also the slices represents the values of the valarray (they are not a copy), but it is designed to be used with numbers and to be a bit optimized, it doesn't have any iterator and cannot be grown. it's doesn't follow the usual STL container concept. but it can still be used as a quick and dirty workaround if you can't use boost.
std::valarray<float> array(16);
// we can view it as a 4x4 matrix.
// this represents the first line
array[std::slice(0,4,1)];
// and the second column
array[std::slice(1,4,4)];
// you cannot use the sliced array directly. they don't
// have operator[], but they have operator=(valarray), and
// valarray has a constructor that takes sliced arrays as input.
What is the speed you are aiming for?
I can image to get a getRow() and getColumn() and getDiagonal()
in constant time when you handle with something list-like in the background.e.g. vector.
(if you just return a pointer)
Should the container grow or is the size fixed after the initialization?
If your container size is m and n you can store m std::vectors of size n,
n std::vectors of size m, and m+n std::vectors of different sizes.
Describing the rows, coloumns, and diagonals.
Then the get methods are easy to implement and in a at() or [] method/operator
three entries are to be changed.