Take item position in vector with structure - c++

Let see code:
struct tmp {
int a;
std::vector <second_struct> b;
}
struct second_struct {
int x;
int y;
}
//main.cpp
int main {
std::vector<tmp> test;
(...); //push data to test
}
So when i push data to test, in second function i want to get vector "b" from this vector 'test'. And find vector b by a;
(i.e I have int a and std::vector<tmp> test; , dont have std::vector <second_struct> b;(from vector test) and want to get it. (vector test is a big array, so i need to do it fastest and using little power )
How to do that? (i suppose std::map will be better? But if you tell me yes, tell me too how to do that in std::Vector)

Loop through test vector checking if tmp::a member is equal to your int a. If so, you have your vector<second_struct> b
for (int i=0;i<test.size();i++) {
if (test[i].a == a) {
// do whatever you need to do with test[i].b
break;
}
}
P.S. map would be easier, just
std::map<int, std::vector<second_struct>> map;
//insert data
std::vector<second_struct> b = map[a]; //assuming it's a that you're looking for

The most straightforward approach is to use map (or unordered_map in C++11). Hope this full example helps:
#include <map>
#include <vector>
#include <iostream>
struct str {
str(int _x, int _y) : x(_x), y(_y) {}
int x, y;
};
std::map<int, std::vector<str> > test;
int main() {
std::vector<str> vec;
for (int i = 0; i < 100; ++i) {
vec.clear();
vec.push_back(str(i, 2 * i));
vec.push_back(str(i + 1, i + 2));
test[i] = vec;
}
std::vector<str> result;
// get some element
result = test[10];
std::cout << "Found at position 10:\n";
for (int i = 0; i < result.size(); ++i)
std::cout << result[i].x << ' ' << result[i].y << '\n';
return 0;
}

Related

Class that uses dynamically generated array

Trying to make a class that can change the contents of a specific element in a dynamically created 2 dimensional array of strings.
So I have a program that creates a 2d array dynamically and later on I want to have a class that takes that array as its argument, along with 2 integers that will be the indexes of a specific element. Later on I'll have it swap the content of that element and scan other elements of the array that it wants to swap it with. For now I'm struggling with even having the class take that array as its argument. I know I'll have to do this by reference and not by value, since the array will be dynamically created, but it seems I am doing it wrong.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Example {
int x, y;
string** chart;
public:
Example(int i, int j,string **arr);
void print() const { cout << x << y << chart[x][y] << endl; }
};
Example::Example(int i, int j,string **arr) {
x = i;
y = j;
**chart = **arr;
}
int main() {
string chart[7][7]; //to make the experiment simpler I haven't
//made the array dynamically generated yet
//but it will be later
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
if (chart[i][j] == "")
chart[i][j].insert(0, 3, ' ');
}
}
chart[6][5] = "EXA";
for (int i = 0; i < 7; i++) {
for (int j = 0; j < 7; j++) {
cout << '[' << chart[i][j] << ']';
}
cout << endl;
}
Example Exa1(6, 5, &chart);
Exa1.print();
return 0;
}
The problem is that the type of &chart is std::string (*)[7][7] which cannot be implicitly converted to a string** and so the constructor Example::Example(int i, int j,string **) cannot be used. This is exactly what the mentioned error says:
error: no matching function for call to 'Example::Example(int, int, std::string (*)[7][7])'
45 | Example Exa1(6, 5, &chart);
To solve this make sure that &chart has the same type as the 3 parameter of your constructor.
Also it would be better to use std::vector.
class Example {
int x, y;
std::vector<std::vector<string>> chart;
public:
Example(int i, int j,const std::vector<std::vector<std::string>> &arr);
};
Example::Example(int i, int j,const std::vector<std::vector<std::string>> &arr)
:x(i),y(j),chart(arr) {
}
int main() {
std::vector<std::vector<std::string>> chart(7, std::vector<std::string>(7));
//pass chart instead of &chart
Example Exa1(6, 5, chart);
}
Working demo
Or you can also use std::array
class Example {
int x, y;
std::array<std::array<std::string, 7>, 7> chart;
public:
Example(int i, int j,const std::array<std::array<std::string, 7>, 7> &arr);
};
Example::Example(int i, int j,const std::array<std::array<std::string, 7>, 7> &arr)
:x(i),y(j),chart(arr) {
}
int main() {
std::array<std::array<std::string, 7>, 7> chart;
//pass chart instead of &chart
Example Exa1(6, 5, chart);
}

C++ : Error could not convert from std::vector<int>* to std::vector<std::vector<int> >

I want to use vector<int> adj[] as my parameter and vector<vector<int>> as my return function type but doing that will cause an error : This happens when returning the vector adj.
could not convert adj from std::vector<int>* to std::vector<std::vector<int> >
return adj;
How can I solve this issue ?
This is my program :
vector<vector<int>>printGraph(int V, vector<int> adj[])
{
for ( int i = 0 ; i < V ; i ++)
{
for (auto x : adj[i])
cout << x;
cout<<"\n";
}
return adj;
}
I realized you are unnecessarily returning adj, if you just want to print you can do yourself a favor and use a void function instead check this code out:
#include <iostream>
#include <vector>
using namespace std;
void printGraph(int V, vector<int> adj[])
{
for (int i = 0; i < V; i++) {
for (auto x : adj[i]) {
cout << x << endl;
}
}
}
int main()
{
vector<int> cat{ 1, 2, 3, 4 };
vector<int> arr[4] = { cat, cat, cat, cat };
printGraph(4, arr);
}
As I got your are trying to convert the array of vectors to a vector of vectors.
Try to return an interval of elements of the original array.
return { adj, adj + V };

C++ Multidimensional Vector

how can I make a table like this with vector in C++:
65 A
66 B
67 C
I did it with a dynamic 2d array like this:
int** ary = new int*[2];
for (int i = 0; i < size; ++i)
ary[i] = new int[size];
// fill the array
for (int i = 0; i < size; i++) {
ary[i][0] = ascii_values[i];
}
for (int i = 0; i < size; i++) {
ary[i][1] = ascii_chars[i];
}
How can I do this with vector?
I was thinking of putting two vectors inside a third vector but I don`t know if that is possible.
P.s. everything has to be dynamic because I will import data from a file
Please help :)
You can easily implement the behaviour above using a vector of std::pair . See the demo:
#include <utility>
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<std::pair<int,char>> result;
std::vector<int> ascii_vals {65, 66, 67};
std::vector<char> ascii_chars {'a', 'b', 'c'};
auto ItA = ascii_vals.begin();
auto ItB = ascii_chars.begin();
while(ItA != ascii_vals.end() && ItB != ascii_chars.end())
{
result.push_back(std::make_pair(*ItA,*ItB));
if(ItA != ascii_vals.end())
{
++ItA;
}
if(ItB != ascii_chars.end())
{
++ItB;
}
}
for(std::vector<std::pair<int, char> >::iterator it = result.begin(); it != result.end(); it++)
std::cout << "(" << it->first << ", " << it->second << ")" << std::endl;
return 0;
}
The code above will print:
(65, a)
(66, b)
(67, c)
Your data is actually not really multidimensional, but rather a list of int, char pairs. Thus the most natural would be a std::vector<std::pair<int,char>>. Imho whenever you can name a pair, you should do so, ie that would be
struct Foo { // I cannot, but you can choose better names
int x;
char y;
};
And create a vector via
std::vector<Foo> f;
For how to use a vector I refer you to the massive amount of material that you can find online.
If however, you already have your data in two vectors, as you mentioned in a comment, then the easiest is probably to use some
struct Bar {
std::vector<char> x;
std::vector<int> y;
};
which may contain the same data, but depending on how you need to process the data it might be more or less efficient compared to the std::vector<Foo> (do you need to access the chars and ints independently or always as those pairs?).

c++ right way to initialize a vector of a struct

i searched a lot here, but there is no right explanation for me, for an advanced newbie in c++. I worked before with vector of structs and now I get segmentation faults...
Thats why I want to know how such objects actually works and if it is the right the way I am doing!
I have a struct like
struct numberOfSpecies {
int predator;
int prey1;
int prey2;
};
and a vector of it:
std::vector<numberOfSpecies> size;
Before I resize it and fill it with values.
size.resize(100);
what is actually this doing? Is this right for a struct?
It looks like it is initialized with zeros...
Now I am doing this like:
size[t].predator=0;
size[t].prey1=0;
size[t].prey2=0;
for(int k = 0; k < N; ++k){
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
Is this right? Where are possible issues? How to do it better?
The easiest and 'correct' solution here is probably to just use the resize() function that belongs to the vector object with aggregate initialization (if you have access to c++11 and on), something like
size.resize(100,{0,0,0}); //aggregate initialization
for(int k = 0; k < N; ++k)
{
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
All members of each numberOfSpecies object will be initialized to 0.
This:
size[t].predator=0;
size[t].prey1=0;
size[t].prey2=0;
will write zeros to the tth element of size - that may or may not be useful:
This:
for(int k = 0; k < N; ++k){
size[t].predator++;
size[t].prey1++;
size[t].prey2++;
}
will increment the tth element of size N times. This seems incredibly unlikely to be useful. I think what you want is:
size[0].predator=0; // Technically not needed because .resize()
size[0].prey1=0; // will have initialized it to zero anyway
size[0].prey2=0; // *BUT* explicit is always better than implicit.
// Initialize each element of size to be one greater than previous.
for(int k = 1; k < N; ++k){
size[k].predator = size[k-1].predator + 1;
size[k].prey1 = size[k-1].prey1 + 1;
size[k].prey2 = size[k-1].prey2 + 1;;
}
Use the value parameter for static parameters.
#include <vector>
struct foo{
int g;
int h;
int l;
};
int main()
{
std::vector<foo> manyFoo(10, {0});
manyFoo.resize(60, {0});
}
If you want to grow your vector as you also put arbitrary values into the struct you could ->
#include <iostream>
#include <vector>
struct foo{
foo(int aG,int aH, int aL):g(aG),h(aH),l(aL) {};
int g;
int h;
int l;
};
int main() {
std::vector<foo> lVec;
for (int i=0;i<10;i++) {
lVec.emplace_back(foo(i,i*2,i*4));
}
int lPos=0;
for (auto &rFoo: lVec) {
std::cout << "Item pos" << lPos++ << " g:" << rFoo.g << " h:" << rFoo.h << " l:" << rFoo.l << std::endl;
}
return EXIT_SUCCESS;
}
If you know the size of the vector and you want to populate it you could ->
#include <iostream>
#include <vector>
struct foo{
foo(int aG,int aH, int aL):g(aG),h(aH),l(aL) {};
int g;
int h;
int l;
};
int main() {
std::vector<foo> lVec(10,{0,0,0});
int lPos = 0;
for (auto &rFoo: lVec) {
rFoo = foo(lPos,lPos*2,lPos*4);
lPos++;
}
lPos=0;
for (auto &rFoo: lVec) {
std::cout << "Item pos" << lPos++ << " g:" << rFoo.g << " h:" << rFoo.h << " l:" << rFoo.l << std::endl;
}
return EXIT_SUCCESS;
}
You could add an default constructor to your structure. The new code will look something like this:
struct numberOfSpecies {
numberOfSpecies (): predator(0), prey1(0), prey2(0) { } // default constructor
int predator;
int prey1;
int prey2;
};
That way, your structure will be properly initialized inside your vector when resize is applied.

What is the optimal way of printing a 2d array vector

I have a function which receive a 2D vector of char from another class and print it
void dat_Output::print_All(Board *board)
{
int x;
int y;
x = 0;
y = 0;
while(x < 26)
{
while(y < 59)
{
std::cout << board->get_Board()[x][y];
y++;
}
std::cout << std::endl;
y = 0;
x++;
}
}
here is the get_Board() function
std::vector<std::vector<char> > Board::get_Board()
{
return(board);
}
My question is for resource efficiency which is the better should I make a copy of the vector at the start of my printing function to avoid calling get_Board() 26*59 time? and whats the difference on resource consuming?
If get_Board() must return a copy, make a single copy before the loops (instead of 26 * 59 copies), and work directly on it. It will also avoid you the board-> indirection.
If possible, return a const reference instead of a copy from get_Board()
Assuming you want to print the entire board, don't use nested while loops, you can use nested for-range loops and avoid explicit indexing.
Minimal example :
#include <iostream>
#include <vector>
class X
{
public :
X() : v({ { 'a', 'b'} , { 'a', 'b' } , { 'c', 'd' } }) {}
const std::vector<std::vector<char>> & GetVector() const { return v; }
private:
std::vector<std::vector<char> > v;
};
int main() {
X x;
const std::vector<std::vector<char> >& v = x.GetVector();
for(auto& v2 : v)
for(auto& c : v2)
std::cout << c << ' ';
}
void dat_Output::print_All(Board *board)
{
std::vector<std::vector<char> > myboard = board->get_Board()[x][y];
int x;
int y;
x = 0;
y = 0;
while(x < 26)
{
while(y < 59)
{
std::cout << myboard[x][y];
y++;
}
std::cout << std::endl;
y = 0;
x++;
}
}
I would create a copy initially. I think every time you call get_Board() you would return a array of vector of vectors and this would be hit on the performance, while calling it once would be cheaper.