Dynamic nested lists - c++

Nested list is a list of lists.
std::list<std::list<int> > nestedList;
How to create multi-dimension depth dynamicly list? For examle, user enters number 3, and then how dynamicly create 3-dimension depth nested list(list of list of lists...) ?
I know how to declare manual, but I need to create it dynamicly.

My go-to approach for simple problems like this is to allocate a vector and handle the dimensions through indexing.
For example, a 2D array of size WxH is std::vector<int> v(W*H);
Then access it with int& get(int x, int y){ return v[y * W + x]; }
You can extend this pattern to as many dimensions as you want, but it may not be suitable depending on your problem. Consider it an option.

You could either:
Predefine what the valid number of dimensions are so all of them can be compiled. Then use a switch and templated functions.
or
Write a new n-d list class.
The constructor would be called along the lines of :
size_t dimensions(3);
ndList<int> myNDList(dimensions);

Related

Is there a way to switch the dimensions order in a multi-dimensional vector?

I have a 3D vector and I want to be able to chose which dimension to plot as a function of another dimension.
So far, I am doing this manually: I create a second 3D vector and re-organize the data accordingly. This solution is not very practical since I need to switch the indexes (inside the nested loop) every time I want to switch the dimensions...
Is there a better/cleaner solution ?
Thanks.
C++ does not provide multidimensional containers for the same reason that containers like std::vector do not provide a standard operator+ etc.: there is no standard that fits everyone's needs (in the case of a + operator, this could be concatenation, element-wise addition, increasing the dimensionality, who knows). If instead of a vector you take a class
<template typename T>
class volume {
private:
std::vector<T> data; // e.g. 3x2 array { 0, 1, 2, 3, 4, 5 }
std::vector<size_t> sizes; // e.g. 3x2 array { 3, 2 }
std::vector<size_t> strides; // e.g. 3x2 array { 1, 3 }
};
then you have all the flexibility you want - no need to stop at 3D!
As an example the data vector of a 3x2 array could be the first 6 natural numbers, the sizes vector would be { 3, 2 } and the strides array { 1, 3 }: in a row (of which there are 2) the elements are next to each other, to increase the row you need to move 3 positions forward.
In the general n-dimensional case you can make an at() operator that takes a vector (or an initializer_list) as a position argument, and the offset corresponding to that position is its inner product with strides.
If you don't feel like programming this from scratch then libraries like Blitz++ already provide this functionality.
No.
<RANT> C++ has no notion of multidimensional vectors. And has poor support for multidimensional arrays, because arrays are far from first class objects. So you are left with vectors of vectors [of vectors ...] and have to carefully control that all vectors in a containing vector have the same size (the language will not help you there). Or with multidimentional raw arrays... provided that the size for all dimensions but the last are known at compile time. </RANT>
As the number of dimensions are known (3D) I would go with a dedicated container using a 1D vector of size l*m*n (where l, m, and n are the size in the 3 dimensions). And a dedicated accessor function data(i,j,k). For there, it is possible to build another accessor tool that gives the data in one dimension starting from another one...
If you do not really like all that boiler plate code, you could have a look at the boost libraries. I do not use it, but if I correctly remember it contains a matrix class...

Graph with std::vectors?

I thought that a cool way of using vectors could be to have one vector class template hold an two separate int variables for x/y-coordinates to graph.
example:
std::vector<int, int> *name*;
// First int. being the x-intercept on a graph
// Second int. being the y-intercept on a graph
(I also understand that I could just make every even/odd location or two separate vectors to classify each x/y-coordinate, but for me I would just like to see if this could work)
However, after making this vector type, I came across an issue with assigning which int within the vector will be written to or extracted from. Could anyone tell me how to best select and std::cout both x/y ints appropriately?
P.S. - My main goal, in using vectors this way, is to make a very basic graph output to Visual Studio terminal. While being able to change individual x/y-intercepts by 'selecting' and changing if needed. These coordinates will be outputted to the terminal via for/while loops.
Also, would anyone like to list out different ways to best make x/y-coordinates with different containers?
Your question rather broad, in other words it is asking for a bit too much. I will just try to give you some pointers from which you can work your way to what you like.
A) equidistant x
If your x values are equidistant, ie 0, 0.5, 1, 1.5 then there is no need to store them, simply use a
std::vector<int> y;
if the number of variables is not known at compile time, otherwise a
std::array<int,N> y;
B) arbitrary x
There are several options that depend on what you actually want to do. For simply storing (x,y)-pairs and printing them on the screen, they all work equally well.
map
std::map<int,int> map_x_to_y = { { 1,1}, {2,4}, {3,9}};
// print on screen
for (const auto& xy : map_x_to_y) {
std::cout << xy.first << ":" xy.second;
}
a vector of pairs
std::vector<std::pair<int,int>> vector_x_and_y = { { 1,1}, {2,4}, {3,9}};
Printing on screen is actually the same as with map. The advantage of the map is that it has its elements ordered, while this is not the case for the vector.
C) not using any container
For leightweight calculations you can consider to not store the (xy) pairs at all, but simply use a function:
int fun(int x) { return x*x; }
TL;DR / more focussed
A vector stores one type. You cannot have a std::vector<int,int>. If you look at the documentation of std::vector you will find that the second template parameter is an allocator (something you probably dont have to care about for some time). If you want to store two values as one element in a vector you either have to use std::vector<std::pair<double,double>> or a different container.
PS
I used std::pair in the examples above. However, I do consider it as good practice to name things whenever I can and leave std::pair for cases when I simply cannot give names better than first and second. In this spirit you can replace std::pair in the above examples with a
struct data_point {
int x;
int y;
};

How to add and read elements of vector of two type of variables

I read this post: vector hold two differents data types
Then I am trying to use this format.
I see in this post two ways to do that:
In my case:
A) std::vector<std::pair<Vecplane3d, CartesianPoint>> vector_super;
B) std::vector<std::tuple<Vecplane3d, CartesianPoint>> vector_super;
But when I want to fill this vector. I am not able to do it.
I coded this:
vector_centroids.push_back(vec_normal, vec_centroid);
And I coded other way:
vector_centroids.insert(vec_normal, vec_centroid);
Sorry but I am looking for documentatio about that and I didn't find anything.
You are manipulating a vector of pair/tuple, even if it aggregates two values, it's still one single element for your std::vector. That's why you have to give your vector a pair or a tuple containing your two aggregated objects:
vector_centroids.push_back({vec_normal, vec_centroid}); //pair
if you are using a tuple do:
vector_centroids.push_back(std::make_tuple(vec_normal, vec_centroid)); //tuple
Would you be able to use a struct like the following:
struct NormalCentroidStruct
{
Vecplane3d normal;
CartesianPoint centroid;
};
Then, when using your vector, you could do as follows:
int main()
{
std::vector<NormalCentroidStruct> vector_centroids;
//Fill vec_normal and vec_centroid
vector_centroids.push_back({vec_normal, vec_centroid});
}

Dynamic multi-dimensional array

I have to create a three-dimensional array using class A as element ,class A is defined like below, should I use vector<vector<vector<A> > > or boost::multi_array? Which one is better?
struct C
{
int C_1;
short C_2;
};
class B
{
public:
bool B_1;
vector<C> C_;
};
class A
{
public:
bool A_1;
B B_[6];
};
If you know the size of all three dimensions at the time, that you write your code, and if you don't need checking for array bounds, then just use traditional arrays:
const int N1 = ...
const int N2 = ...
const int N3 = ...
A a[N1][N2][N3]
If the array dimensions can onlybe determined at run time, but remain constant after program initialization, and if array usage is distributed uniformly, then boost::multi_array is your friend. However, if a lot of dynamic extension is going on at runtime, and/or if array sizes are not uniform (for example, you need A[0][0][0...99] but only A[2][3][0...3]), then the nested vector is likely the best solution. In the case of non-uniform sizes, put the dimension, whose size variies the most, as last dimension. Also, in the nested vector solution, it is generally a good idea to put small dimensions first.
The main concern that I would have about using vector<vector<vector<A> > > would be making sure that the second- and third-level vectors all have the same length like they would in a traditional 3D array, since there would be nothing in the data type to enforce that. I'm not terribly familiar with boost::multi_array, but it looks like this isn't an issue there - you can resize() the whole array, but unless I'm mistaken you can't accidentally remove an item from the third row and leave it a different size than all of the other rows (for example).
So assuming concerns like file size and compile time aren't much of an issue, I would think you'd want boost::multi_array. If those things are an issue, you might want to consider using a plain-old 3D array, since that should beat either of the other two options hands-down in those areas.

The knights tour. Chosing a container

I have been reading up on C++ lately, especially STL, and I decided to do the Knights Tour problem again. I'm thinking about the best way to implement this, and I'm looking for some help.
Just for fun and practice, I thought I'd start with a "Piece" base class, which a "Knight" class can inherit from. I want to do this so I later can try adding other pieces(even though most of the pieces can't walk over the whole board and complete the problem).
So the "piece class" will need some sort of container to store the coordinates of the piece on the board and the number of moves it has made in that specific step.
I'm thinking I need a linked list with 64 (8 * 8) places to do this most efficiently, containing x,y and moves.
Looking at the STL containers, I can't find anything except map that will hold more than one type.
What can I do to store the coordinate pair and an int for the number of moves in one container? Are there more efficient ways of doing this than using vector, list or map? Do I need a custom container?
Thanks!
You can use
struct CellInfo
{
int x, y, move_count;
}
And store it in std::vector for constant access.
Apart from STL and encapsulation, a very efficient way is to use arrays:
pair<int, int> piece_pos[N];
int piece_move[N];
This avoids the overhead of memory leakage and is faster than dynamic allocation.
If you stell want to use STL, then:
vector<pair<int, int> > piece_pos(N);
vector<int> piece(N);
The C++ STL now has static arrays as well. If you want to store the number of times a given x,y coordinate has been moved to, you can create an array of arrays like the following:
using container_type = std::array<std::array<int, 8>, 8>;
// ...
container_type c;
int moves = c[x][y]; // constant-time access.
If you don't need to look moves up based on x,y, and just want the data stored efficiently, use a flat array of size 8x8 = 64.
If your compiler is out of date, consider using std::vector instead.