Array of Arrays for use in a For loop - c++

array<string, 7> month31={"January","March","May","July","August","October","December"};
array<string, 4> month30 ={"April","June","September","November"};
array<string, 1> month29 = {"February"};
array<string, 1> month28 = {"February"};
array<string, 4> months= {month31,month30,month29,month28};
I know in python this would work but it keeps crashing. Is there a syntax I am missing?
End goal is to use a for loop to move between the arrays, but if I can't figure that out in time I will have to hard code it all and that will be a pain.

You'll likely be better off using std::vector<std::string> for your (individual) month lists and then a std::array< std::vector<string> > for your composite (note that a std::array of std::array<string, n> would require the element arrays to all be the same length).
Here's a short, illustrative example:
#include <iostream>
#include <string>
#include <array>
#include <vector>
int main()
{
std::vector<std::string> month31 = { "January","March","May","July","August","October","December" };
std::vector<std::string> month30 = { "April","June","September","November" };
std::vector<std::string> month29 = { "February" };
std::vector<std::string> month28 = { "February" };
// The composite list can be a container of the above vector types ...
std::array< std::vector<std::string>, 4 > months = { month31, month30, month29, month28 };
for (auto& vec : months) { // Take REFERENCES (&) to avoid copying.
std::cout << "--- Next List... ---" << std::endl;
for (auto& month : vec) {
std::cout << month << std::endl;
}
}
return 0;
}
Or, you could also use std::vector for the composite; with all other lines in the above code unchanged, just use this for the declaration of months:
std::vector< std::vector<std::string> > months = { month31, month30, month29, month28 };
The (main) difference between vector and array is that, for array, the size, which is fixed at compile time and specified as a template parameter, is also part of the actual type of the object. So, for your 4 components of different lengths, defining each as a std::array would make them types of 4 (or 3, actually) different classes (so they would not be suitable as members of a 'composite' array / vector container).

You declared months as an array of (four) strings, but you want to initialize it with arrays (of strings) - the types don't match. What's more, you want to keep all those arrays in one, while they are all different sizes. Even with auto it wouldn't work.
What you can do is use vector, like:
vector<string> month31 = {"January","March","May","July","August","October","December"};
vector<string> month30 ={"April","June","September","November"};
vector<string> month29 = {"February"};
vector<string> month28 = {"February"};
vector<vector<string>> months= {month31,month30,month29,month28};

Related

Copy vector of vectors into 1D array

I have following C++ object
std::vector<std::vector<SomeClass>> someClassVectors(sizeOFOuter);
where I know the size of "outer" vector, but sizes of "inner" vectors varies. I need to copy the elements of this structure into 1D array like this:
SomeClass * someClassArray;
I have a solution where I use std::copy like this
int count = 0;
for (int i = 0; i < sizeOfOuter; i++)
{
std::copy(someClassVectors[i].begin(), someClassVectors[i].end(), &someClassArray[count]);
count += someClassVectors[i].size();
}
but the class includes large matrices which means I cannot have the "vectors" structure and 1D array allocated twice at the same time.
Any ideas?
Do you previously preallocate someClassArray to a given size? I'd suggest using 1D vector for getting rid of known problems with the plain array if possible.
what about something like this:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<std::vector<int>> someClassVectors {
{1,2,3},
{4,5,6},
{7,8,9}
};
std::vector<int> flat;
while (!someClassVectors.empty())
{
auto& last = someClassVectors.back();
std::move(std::rbegin(last), std::rend(last), std::back_inserter(flat));
someClassVectors.pop_back();
}
std::reverse(std::begin(flat), std::end(flat));
int * someClassArray = flat.data();
std::copy(someClassArray, someClassArray + flat.size(), std::ostream_iterator<int>(std::cout, " "));
}
The extra reverse operation doesn't have an effect on memory metrics - such an approach helps to avoid unneeded memory reallocations resulting from removing vector elements from beginning to end.
EDIT
Inspired by comments I changed copy to move semantics
Embrace Range-v3 (or whatever will be introduced in C++20) and write a solution in (almost) a single line:
auto flattenedRange = ranges::views::join(someClassVectors);
this gives you a range in flattenedRange, which you can loop over or copy somewhere else easily.
This is a possible use case:
#include <iostream>
#include <vector>
#include <range/v3/view/join.hpp>
int main()
{
std::vector<std::vector<int>> Ints2D = {
{1,2,3},
{4},
{5,6}
};
auto Ints1D = ranges::views::join(Ints2D);
// here, going from Ints1D to a C-style array is easy, and shown in the other answer already
for (auto const& Int : Ints1D) {
std::cout << Int << ' ';
}
std::cout << '\n';
// output is: 1 2 3 4 5 6
}
In case you want to get a true std::vector instead of a range, before writing it into a C-style array, you can include this other header
#include <range/v3/range/conversion.hpp>
and pipe join's output into a conversion function:
auto Ints1D = ranges::views::join(Ints2D) | ranges::to_vector;
// auto deduces std::vector<int>
In terms of standard and versions, it doesn't really require much. In this demo you can see that it compiles and runs just fine with
compiler GCC 7.3
library Range-v3 0.9.1
C++14 standard (option -std=c++14 to g++)
As regards the copies
ranges::views::join(Ints2D) is only creating a view on Ints2D, so no copy happens; if view doesn't make sense to you, you might want to give a look at Chapter 7 from Functional Programming in C++, which has a very clear explanation of ranges, with pictures and everything;¹
even assigning that output to a variable, auto Ints1D = ranges::views::join(Ints2D);, does not trigger a copy; Ints1D in this case is not a std::vector<int>, even though it behaves as one when we loop on it (behaves as a vector because it's a view on it);
converting it to a vector, e.g. via | ranges::to_vector, obviously triggers a copy, because you are no more requesting a view on a vector, but a true one;
passing the range to an algorithm which loops on its elements doesn't trigger a copy.
Here's an example code that you can try out:
// STL
#include <iostream>
#include <vector>
// Boost and Range-v3
#include <boost/range/algorithm/for_each.hpp>
#include <range/v3/view/join.hpp>
#include <range/v3/range/conversion.hpp>
struct A {
A() = default;
A(A const&) { std::cout << "copy ctor\n"; };
};
int main()
{
std::vector<std::vector<A>> Ints2D = {
{A{},A{}},
{A{},A{}}
};
using boost::range::for_each;
using ranges::to_vector;
using ranges::views::join;
std::cout << "no copy, because you're happy with the range\n";
auto Ints1Dview = join(Ints2D);
std::cout << "copy, because you want a true vector\n";
auto Ints1D = join(Ints2D) | to_vector;
std::cout << "copy, despite the refernce, because you need a true vector\n";
auto const& Ints1Dref = join(Ints2D) | to_vector;
std::cout << "no copy, because we movedd\n";
auto const& Ints1Dref_ = join(std::move(Ints2D)) | to_vector;
std::cout << "no copy\n";
for_each(join(Ints2D), [](auto const&){ std::cout << "hello\n"; });
}
¹ In an attempt to try giving a clue of what a range is, I would say that you can imagine it as a thing wrapping two iterators, one poiting to the end of the range, the other one pointing to the begin of the range, the latter being incrementable via operator++; this opearator will take care of the jumps in the correct way, for instance, after viewing the element 3 in Ints2D (which is in Ints2D[0][2]), operator++ will make the iterator jump to view the elment Ints[1][0].

Efficient way of creating an array/vector of strings and finding out the length of all strings in it

I want to create a function in which I can iterate over an array/vector containing a variable amount of strings, and I need to know the length of the strings before I send them to the function. How can I achieve this in an efficient way?
I have some loose idea of the function, but how do I efficiently sent an array/vector of strings to it and the size of all those strings combined. For example, the function could look something like this:
myFunc(vector<string> s, int totalWordLength) {
// Loop over strings in vector.
}
I could do something like this to create a vector of strings.
const char *args[] = {"12345", "678"};
vector<string> s(args, end(args));
But how do I then find out the size of the strings (8) in this without looping through it so that I can send it to myFunc(s, sizeOfStrings)?
If you have an idea to achieve the same result, by using an array instead or something, please let me know. I'm trying to do this as efficient as possible.
Iterate through container (container class irrelevant)
const char *args[] = {"12345", "678"};
vector<string> s(args, end(args));
size_t sizOfS = 0;
for( auto& item : s )
sizOfS += item.length();
Another way unites process of filling array and calculating length:
const char *args[] = {"12345", "678"};
std::vector<std::string> s;
s.reserve(sizeof(args)/sizeof(args[0]));
size_t sizOfS = 0;
for( const std::string& item : args )
{
sizOfS += item.length();
s.push_back(item);
}
Regardless of what you do, cost of the process would be O(n), where n = strings * their-total-length. There is no other defined way, but several functions which can turn loop into one-liner. Even if define your own container that would track length of strings, its cost would have same order.
Which container to use depends on what kind of actions you expect to perform, vector got constant cost of random access to container items, but linearly increasing cost of growing its storage. list may have cheap insertion\push cost but it got sequential iterator.
If you want to know the lengths of all of the strings in the vector and query it often (its not a one-off thing) then you can calculate the length of the strings when they are added together and store the total with the vector.
A quick example of this with a class:
class MyClassFoo {
public:
std::vector<std::string> items;
std::size_t total_item_sizes = 0;
void addItem(const std::string& item) {
total_item_sizes += item.length(); // Add its length to the total
items.emplace_back(item); // Add the item to the vector
}
}
Then you can pass this object around and query it.
If you want to be more efficent pass by reference or move single use parameters. This is important with something like a std::vector as you probably don't want to copy all it's elements.
As an aside it is unlikely this is actually neccasary, unless you are trying to sum the lengths of all the strings very frequently and there are a lot of them, your bottleneck will not be iterating over an std::vector. Your demand for 'efficency' smells like premature optimisation. Remember the 20-80 rule (80% of your program execution time is spent running 20% of your code).
Given your scenario, an approach could be to calculate the length of the strings at the time of construction of the vector.
One solution using a variadic template could be a wrapper like this (live):
#include <iostream>
#include <vector>
#include <string>
struct V
{
template <typename ... T>
V( T&& ... t ) : v{ std::forward<T>(t)... }
{
for ( const auto& s : v ) size += s.size();
}
std::vector<std::string> v;
std::size_t size {0};
};
int main()
{
const char *args[] = { "12345678", "6789", "1234", "5678" };
V obj ( std::begin(args), std::end(args) );
std::cout << "No. of Strings : " << obj.v.size() << '\n';
std::cout << "Total Length : " << obj.size << '\n';
return 0;
}
Output:
No. of Strings : 4
Total Length : 20

C++ Create array with dynamic name

I need a create array in c++ but I need array always with variables name
int Magic(string name_array,int n)
{
string Name = "Something";
Name.append(name_array);
double * Name = new double[n];
}
int main()
{
Magic("a.txt",10);
}
And I have this error:
operator' : 'identifier1' differs in levels of indirection from 'identifier2'
I know it's not a python but maybe a map help me? How I can make this?
If you want to be able to access different arrays by string names, consider using a std::map<std::string, std::vector<double>>. This maps strings to C++'s better, more dynamic answer to arrays. In this case your code would be something like:
#include <iostream>
#include <map>
#include <vector>
void AddVector(std::map<std::string, std::vector<double>> &io_map,
const std::string& i_name,
const std::size_t i_size)
{
io_map[i_name].resize(i_size);
}
int main()
{
std::map<std::string, std::vector<double>> vector_map;
AddVector(vector_map, "Vector1", 3);
AddVector(vector_map, "Vector2", 10);
std::cout << "Vector with string key Vector1 has size: " << vector_map["Vector1"].size() << std::endl;
return 0;
}
In this code I've tried to be as close to the code you've given - resizing the vectors to the size you would have created the array in your "Magic" function. However, vectors can dynamically resize, so you may not even need to create/resize them in your code depending on your use case.

Structure that contains vectors with different sizes, cpp

I wish to declare a structure, say with size n=10, that in each i site of the structure there is a vector. The vectors in the sites of the structure have different sizes.
In matlab it can be obtained using struct. how it is done in C++?
I think what you are looking for is an array, or a vector, of vectors.
For example:
#include <array>
#include <vector>
#include <iostream>
int main ()
{
std::array<std::vector<int>, 10> Vectors;
for (auto &i : Vectors) //Loop through all 10 vectors in Vectors
{
for (int j=0; j<5; j++) //Push 1, 2, 3, 4, and 5 into each vector
{
i.push_back(j);
}
}
return 0;
}
struct S {
std::array<std::vector<int>, 10> data;
};
You can also use an alias as well:
using arrayOfTenVectors = std::array<std::vector<int>, 10>;
Of course int is a placeholder. You can make either the struct or the alias a template and use some T inside of the vector.

Sorting static multi dimentional array with custom compare function

There are examples of sorting vectors or dynamically allocated arrays but I couldn't find any help regarding static arrays. Let's say I have an array
int array[10][10];
and a compare function,
bool compare(const int (*a)[10], const int (*b)[10]);
When I call it like this,
std::sort(array, array + 10, compare);
I have compilation errors: error: cannot convert 'int*' to 'const int (*)[10]' in argument passing
I tried many ways, casting array to (void**) in sort function but then I have segmentation fault. My problem is using arrays as function parameters I guess but I couldn't figure out how to use this std::sort. Otherwise, I will have to write my own sort function.
When std::sort is called on a container of elements of type T, the comparison function needs to receive arguments of type T or const T&. In this case, you have a 2-dimensional array, so the type of elements is a 1-dimensional array int[10]. Since 1-dimensional arrays decay to pointers, compare can be:
bool compare(int a[10], int b[10]);
or equivalently:
bool compare(int *a, int *b);
This will fix the error you got, but your code still won't work: std::sort needs the container elements to be assignable (or movable in C++11), but arrays are not assignable.
You can use std::vector<std::vector<int> > instead as people have suggested. Note that your fear of performance problems is misguided: Even if sorting a two-dimensional array was possible, it would involve a lot of copying of one-dimensional arrays which would take a long time. Swapping vectors, on the other hand, is done by simply swapping pointers which is faster. In general, you should not make assumptions about performance if you haven't tested it first.
The comparison function doesn't get an iterator to the element passed but the dereferenced iterator, i.e., the value type. Thus, your comparison function would need to be declared as like the one below:
bool compare(int (&a0)[10], int (&a1)[10]);
You can verify that you can actually call it with array iterators:
compare(*(std::begin(array) + 0), *(std::begin(array) + 1));
However, this won't make it possible to sort you arrays: built-in arrays are not copy-assignable. The easiest way to sort statically sized arrays (where the outer dimension flexible) is to use std::array<T, N>:
std::array<int, 10> array[10];
std::sort(std::begin(array), std::end(array));
I say, if we're gonna use the STL and C++ .. lets write it in a modern style and really use the STL.
My attempt at the problem using modern c++11:
#include <vector>
#include <iostream>
#include <algorithm>
typedef std::vector<int> ArrayInt;
typedef std::vector< std::vector<int> > ArrayData;
bool compare(const ArrayInt& a, const ArrayInt& b) {
std::cout << &(a) << ' ' << &(b) << std::endl;
int sumA = std::accumulate(a.begin(), a.end(), 0);
int sumB = std::accumulate(b.begin(), b.end(), 0);
return sumA < sumB;
}
int main(int argc, char** argv) {
ArrayData array = {
{1,2,4,0,3,7,6,8,3,3},
{13,2,4,0,3,7,6,8,3,3},
{10,2,4,0,3,7,6,8,3,3},
{1,2,4,0,3,7,6,8,3,3},
{16,2,4,0,3,7,6,8,3,3},
{1,2,400,0,3,7,6,8,3,3},
{1,2,4,0,3,7,6,8,3,3},
{120,2,4,0,3,7,6,8,3,3},
{1,2,4,0,3,7,6,8,3,3},
{1,2,4,0,3,7,6,8,3,3}
};
std::sort(array.begin(), array.end(), compare);
for (auto row : array) {
for (int num : row)
std::cout << num << ' ';
std::cout << std::endl;
}
}
It uses accumulate to sum each sub array, and sorts on the sum .. it's super inefficient because it has to sum the same row multiple times .. but it's just there to show off a custom compare function.
As an exercise, I wrote this version that uses async to distribute the summing part over any available cores to do the summing, before the sort. I'm sorry it's getting a bit off topic. I hope it's still useful to some people:
#include <vector>
#include <iostream>
#include <algorithm>
#include <future>
typedef std::vector<int> IntRow;
typedef std::pair<int, IntRow> DataRow;
typedef std::vector<DataRow> DataTable;
int main(int argc, char** argv) {
// Holds the sum of each row, plus the data itself
DataTable array = {
{0, {1,2,4,0,3,7,6,8,3,3}},
{0, {13,2,4,0,3,7,6,8,3,3}},
{0, {10,2,4,0,3,7,6,8,3,3}},
{0, {1,2,4,0,3,7,6,8,3,3}},
{0, {16,2,4,0,3,7,6,8,3,3}},
{0, {1,2,400,0,3,7,6,8,3,3}},
{0, {1,2,4,0,3,7,6,8,3,3}},
{0, {120,2,4,0,3,7,6,8,3,3}},
{0, {1,2,4,0,3,7,6,8,3,3}},
{0, {1,2,4,0,3,7,6,8,3,3}}
};
// Make use of multiple cores if it's efficient enough
// get the sum of each data row
std::vector<std::future<int>> sums(array.size());
auto next = sums.begin();
for (auto& row : array)
*next++ = std::async([](const IntRow& row) { return std::accumulate(row.begin(), row.end(), 0); }, row.second);
// Get the results
auto nextRow = array.begin();
for (auto& sum: sums)
(*nextRow++).first = sum.get();
// Sort it
std::sort(array.begin(), array.end(),
[](const DataRow& a, const DataRow& b) { return a.first < b.first; });
// Print it
for (auto row : array) {
for (int num : row.second)
std::cout << num << ' ';
std::cout << std::endl;
}
}
It needs to be compiled with pthread library or similar:
g++ -O6 sort.cpp --std=c++11 -g -lpthread