C++ Multidimensional Vector - c++

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?).

Related

How do I order an array of strings on the basis of an array of integers

I have an array of integers with a bunch of numbers from 1-10
Then I have an array of names(strings) which belong with the numbers a.e.
Numbers[0] = 5, Numbers[1] = 2
Names[0] = "Jeremy", Names [1] = "Samantha".
I can easily order the numbers with:
int n = sizeof(Numbers) / sizeof(Numbers[0]);
sort(Numbers, Numbers + n, greater<int>());
But then the names and numbers don't match at all.
How do I fix this?
A very common approach is to create an array of indices and sort that:
std::vector<int> indices(Numbers.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(),
[&](int A, int B) -> bool {
return Numbers[A] < Numbers[B];
});
The original arrays are not altered, but now indices can be used to access both arrays in the desired order.
If we want to reorder Numbers or Names in place, then we can
create a set of "back indices" that record where to find the element i in the sorted array:
std::vector<int> back_indices(indices.size());
for (size_t i = 0; i < indices.size(); i++)
back_indices[indices[i]] = i;
Now we can reorder, for example, Names in place in the desired order:
int index = 0;
std::string name = Names[index];
for (int i = 0; i < back_indices.size(); i++) {
index = back_indices[index];
std::swap(name,Names[index]);
}
I've tested this code which should give you the required behavior:
struct numberName {
int num;
string name;
};
bool compare(numberName a, numberName b){
return a.num < b.num; // if equal, no need to sort.
}
int main() {
numberName list[2];
list[0].num = 5, list[1].num = 2;
list[0].name = "Jeremy", list[1].name = "Samantha";
sort(list, list+2, compare);
}
Like HAL9000 said, you want to use a struct since this keeps variables that belong to each other together. Alternatively you could use a pair, but I don't know if a pair would be good practice for your situation or not.
This is a great example of the complexities introduced by using parallel arrays.
If you insist on keeping them as parallel arrays, here is a possible approach. Create a vector of integer indexes, initialised to { 0, 1, 2, 3, etc }. Each integer represents one position in your array. Sort your vector of indexes using a custom comparision function that uses the indexes to refer to array1 (Numbers). When finished you can use the sorted indexes to reorder array1 and array2 (Names).
One could also write their own sort algorithm that performs swaps on the extra array at the same time.
Or one could trick std::sort into sorting both arrays simultaneously by using a cleverly designed proxy. I will demonstrate that such a thing is possible, although the code below may be considered a simple hackish proof of concept.
Tricking std::sort with a cleverly-designed proxy
#include <iostream>
#include <algorithm>
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
int tempNumber;
std::string tempName;
class aproxy {
public:
const size_t index = 0;
const bool isTemp = false;
aproxy(size_t i) : index(i) {}
aproxy() = delete;
aproxy(const aproxy& b) : isTemp(true)
{
tempName = Names[b.index];
tempNumber = Numbers[b.index];
}
void operator=(const aproxy& b) {
if(b.isTemp) {
Names[index] = tempName;
Numbers[index] = tempNumber;
} else {
Names[index] = Names[b.index];
Numbers[index] = Numbers[b.index];
}
}
bool operator<(const aproxy& other) {
return Numbers[index] < Numbers[other.index];
}
};
int main() {
aproxy toSort[SZ] = {0, 1};
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
...and an even more cleverly-designed proxy could avoid entirely the need to allocate SZ "aproxy" elements.
Tricking std::sort with an "even more cleverly-designed" proxy
#include <iostream>
#include <algorithm>
class aproxy;
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
aproxy *tempProxyPtr = nullptr;
int tempNumber;
std::string tempName;
class aproxy {
public:
size_t index() const
{
return (this - reinterpret_cast<aproxy*>(Numbers));
}
bool isTemp() const
{
return (this == tempProxyPtr);
}
~aproxy()
{
if(isTemp()) tempProxyPtr = nullptr;
}
aproxy() {}
aproxy(const aproxy& b)
{
tempProxyPtr = this;
tempName = Names[b.index()];
tempNumber = Numbers[b.index()];
}
void operator=(const aproxy& b) {
if(b.isTemp()) {
Names[index()] = tempName;
Numbers[index()] = tempNumber;
} else {
Names[index()] = Names[b.index()];
Numbers[index()] = Numbers[b.index()];
}
}
bool operator<(const aproxy& other) {
return Numbers[index()] < Numbers[other.index()];
}
};
int main() {
aproxy* toSort = reinterpret_cast<aproxy*>(Numbers);
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
Disclaimer: although my final example above may technically be in violation of the strict-aliasing rule (due to accessing the same space in memory as two different types), the underlying memory is only used for addressing space-- not modified-- and it does seems to work fine when I tested it. Also it relies entirely on std::sort being written in a certain way: using a single temp variable initialized via copy construction, single-threaded, etc. Putting together all these assumptions it may be a convenient trick but not very portable so use at your own risk.

Using functions on vectors in C++

I'm trying to change the data inside a vector's element by using a function. It happens that the elements are changed just inside the function. How can I keep the changings outside the function? Do I must use pointers?
The code:
#include <iostream>
#include <vector>
using namespace std;
void populate( int size_, vector<int> pop)
{
//Set the vector's size and populate the vector
pop.resize(size_);
for(int i = 0; i<3 ; i++)
{
pop[i] = i;
}
}
int main()
{
vector<int> vec;
int size = 3;
populate(size, vec);
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
The output at cout should be : 0 1 2
But it is empty.
What you're trying to do is easily and idiomaticaly done with standard library facilities:
int size = 3;
std::vector<int> vec(size);
std::iota(vec.begin(), vec.end(), 0); // include algorithm for this
You need to take the vector by reference
void populate( int size_, vector<int>& pop)
Otherwise you are passing in a copy of the vector, populating it, then returning, but the original vector is unmodified.
Or as #juanchopanza recommended, since the sole purpose of this function is to make this vector for you, it could be
vector<int> populate( int size_ )
{
vector<int> temp(size_);
for(int i = 0; i < size_ ; i++)
{
pop[i] = i;
}
return temp;
}
Then
int main()
{
int size = 3;
vector<int> vec = populate(size, vec);
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
You are sending in the vector to populate by value. This creates a copy, so pop is a copy of vec. Changes you make only affect pop.

Getting Value from particular index in 2d vector in c++

I have made a 2d vector using :
std::vector<std::vector<int> *> hp;
I want to initialise hp vector and get the data from particular index for the same.
for eg,
Getting the values from hp[2][2];
Please do help
Try the following
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int> *> hp =
{
new std::vector<int> { 1, 2, 3 },
new std::vector<int> { 4, 5, 6 }
};
for ( std::vector<std::vector<int> *>::size_type i = 0;
i < hp.size(); i++ )
{
for ( std::vector<int>::size_type j = 0; j < hp[i]->size(); j++ )
{
std::cout << ( *hp[i] )[j] << ' ';
// std::cout << hp[i]->operator[]( j ) << ' ';
}
std::cout << std::endl;
}
for ( auto &v : hp ) delete v;
return 0;
}
For commented and uncommented statements within the inner loop the program output will be the same and look like
1 2 3
4 5 6
Note that
std::vector<std::vector<int>*> hp
defines a std::vector containing pointers to objects of type
std::vector<int>
As ravi mentioned, you probably want
std::vector<std::vector<int>> hp;
But if you insist on having a vector with pointers,
std::vector<std::vector<int>*> hp;
(*hp[2])[2] // retrieves third value from third std::vector<int>
Remark: In C++11 (also called C++0x) you don't need the spacing between the ">" (as I wrote in the examples).
If these are pointers to vectors that are owned elsewhere:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
// Create owning vector
std::vector<std::vector<int>> h = {{0,1,2},{3,4,5},{6,7,8}};
// Create vector of pointers
std::vector<std::vector<int>*> hp(h.size());
//auto get_pointer = [](std::vector<int>& v){return &v;}; // C++11
auto get_pointer = [](auto& v){return &v;}; // C++14
std::transform(h.begin(), h.end(), hp.begin(), get_pointer);
// Output value in third column of third row
std::cout << (*hp[2])[2];
}

Take item position in vector with structure

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;
}

C++ store iterators in a SET

In my program I have a set: ( std::set<int> myset; ) and after some treatment I finally take one iterator which I have decelerated like this ( set<int>::iterator findnumb; ). Well let say I have to do this 5 times in MYSET, 5 times define differences iterators (it1, it2 ,....it5) and not only this but after that to sort them by the content that they show. My idea it was to create a loop and in every time put the specific iterator in a set and sort but I don't know how I declare this.
I create an simple example that take for user 5 number and finds the nearest bigger from our set and print it. But in every loop the old iterator replace from the new one and in my real program I want to store this iterator int a set. Well based on this can you modify this example and store the iterators in a set sort by the content that they show.
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
std::set<int> myset;
for (int i=1; i<=20; ++i)
{myset.insert(i*10);}
vector<int> vect;
int numb;
for (int i=0; i<5; ++i)
{
cout << "give a number" <<endl;
cin >> numb;
vect.push_back(numb);
}
set<int>::iterator findnumb;
for (vector<int>::iterator it = vect.begin(); it != vect.end(); ++it)
{
findnumb=myset.find(*it);
while ( (*findnumb)!=(*it))
{ ++(*it); findnumb=myset.find(*it);}
cout << *findnumb<<" ";
}
cout << endl;
return 0;
}
I am not sure if I understood your question correctly.
struct dereferenced_less {
template<typename I>
bool operator()(const I& lh, const I& rh) const { return *lh < *rh; }
};
int main()
{
using namespace std;
set<int> myset = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
vector<int> vect = { 17, 32, 4, 16, 28, 120 };
set<set<int>::const_iterator, dereferenced_less> findnumbs;
for (int i : vect)
{
auto findnumb = myset.upper_bound(i);
if (findnumb != end(myset))
findnumbs.insert(findnumb);
}
// findnumbs: {10, 20, 30, 40}
}
If you only want the iterators ordered it might be better to sort the input vector and process the set skipping dupklicate elements.
vector<set<int>::const_iterator> result;
sort(begin(vect), end(vect));
for (int i : vect)
{
auto find = myset.upper_bound(i);
if (find != end(myset) && (result.empty() || *result.back() != *find))
result.push_back(find);
}
Don't use sets where you can use vectors.
and this
for (vector<int>::iterator it = vect.begin(); it != vect.end(); ++it)
is NOT how you traverse a vector!!! Iterators are made to be used in template algorithms, an on containers that cannot be randomly accessed. This is how you use vectors
for (size_t i = 0; i < vect.size(); ++ i)
vec[i] // the i-th element
Or with the new syntax
for (int x : vect)
x // the i-th element
Also find will allways find the element in the set, when not it will return the end iterator, that's after the very last element
so this
findnumb=myset.find(*it);
while ( (*findnumb)!=(*it))
{ ++(*it); findnumb=myset.find(*it);}
is useless and wrong. To test if find found the element use
if (findnumb != myset.end())
Of course if all you want to know is whether or not the element is in the set, it's better to use count and forget about the iterators at all.
if (myset.count(x) > 0)
And don't store iterators if you only want to read the value not write it. Just store the value itself
with the help of hansmaad I found out what I need (baste on my code) thanks a lot.!!!!!!!!!!! Also I have a last question, how I use FIND in set findnumbs!!!! like set::const_iterator, dereferenced_less>::iterator ithelp; ithelp=findnumbs.find(20)
#
include <iostream>
#include <set>
#include <vector>
#include <algorithm>
struct dereferenced_less {
template<typename I>
bool operator()(const I& lh, const I& rh) const { return *lh < *rh; }
};
int main()
{
using namespace std;
set<int> myset;
for (int i=1; i<=10; ++i)
{myset.insert(i*10);}
int vc[] = { 17, 32, 4, 16, 28 };
vector<int> vect ;
vect.assign (vc, vc+5);
set<set<int>::const_iterator, dereferenced_less> findnumbs;
set<int>::iterator findnumb;
for (std::vector<int>::iterator i = vect.begin(); i != vect.end(); ++i)
{ cout << *i << endl; }
for (std::vector<int>::iterator i = vect.begin(); i != vect.end(); ++i)
{
findnumb = myset.find(*i);
while ( (*findnumb)!=(*i))
{ ++(*i); findnumb=myset.find(*i);}
findnumbs.insert(findnumb);
cout << *findnumb<<" ";
}
for (set<set<int>::const_iterator, dereferenced_less>::iterator it=findnumbs.begin(); it!=findnumbs.end(); ++it)
std::cout << ' ' << *(*it);
std::cout << '\n';
return 0;
}