How to copy a value inside an array - c++

I have an integer array and the fifth value should always be similar to the first value.
For example, if i have:
int test[] ={1,2,3,4,1}
and if I say:
test[0]= 5
The array should look like: 5 2 3 4 5.
Is there some way to do this? I tried with pointers, but couldn't get a good result.

Test it on GodBolt
Using actual C++ syntax instead of C:
#include <array>
#include <iostream>
void print_list(std::array<int*, 5> const& list){
for( auto const& item : list ){
std::cout << *item << "\t";
}
std::cout << "\n";
}
int main(){
std::array<int, 4> n = {1, 2, 3, 4};
std::array<int*, 5> list = {&n[0], &n[1], &n[2], &n[3], &n[0]};
print_list(list);
*list[0] = 3;
print_list(list);
}

Not possible with integers but pointers would do the trick, see here: https://www.tutorialspoint.com/cplusplus/cpp_array_of_pointers.htm
Something like:
int *sharedNumber = new int(1);
int* ptr[] = {sharedNumber, new int(2), new int(3), new int(4), sharedNumber};
cout<<"values are "<<*ptr[0]<<" "<<*ptr[4]<<"\n";
*sharedNumber = 5;
cout<<"values are "<<*ptr[0]<<" "<<*ptr[4]<<"\n";
Will show 'value is 1' and 'value is 5' for ptr[1] and ptr[4] - just make sure to delete initialised memory to avoid memory leaks.

There is currently no way of doing what you want with the syntax you're providing. Your options, which would (minimally) alter your code are:
Manually setting two elements to the same value (see the comments below your question);
Writing a function for mutating elements that automatically synchronizes the first and fifth elements;
Storing an array of pointers (which seems to be your attempt);
Sharing state between elements of the array so that affecting one element would also change other elements, and that way "synchronizing" their values;
Wrapping your array into a class that manages that array.
It should seem obvious which solutions are, most likely, overkill.
Here is a very simple simple implementation of the second option:
void setElement(int* array, size_t index, int value)
{
array[index] = value;
if (index == 0)
array[4] = value;
if (index == 4)
array[0] = value;
}
Keep in mind that using std::array, std::vector or iterators would probably be a better choice than C-style arrays and raw pointers.

There's a way to achieve this effect for a custom wrapper type, but not for arrays:
Just implement a custom [] operator:
template<class ElementType, size_t arraySize>
class MyArray
{
public:
using value_type = ElementType;
constexpr MyArray() = default;
constexpr MyArray(std::initializer_list<ElementType> arr)
{
std::copy_n(arr.begin(), (std::min)(arraySize, arr.size()), m_data);
}
constexpr size_t size() const
{
return arraySize;
}
constexpr ElementType& operator[](size_t index)
{
return m_data[index % arraySize];
}
constexpr ElementType const& operator[](size_t index) const
{
return m_data[index % arraySize];
}
private:
ElementType m_data[arraySize];
};
int main()
{
MyArray<int, 4> a = { 1, 2, 3, 4 };
std::cout << a[4] << '\n';
a[0] = 5;
std::cout << a[4] << '\n';
}
Note that this just "wraps around"; not only can you access the first element using index 4, but for every index passed the remainder of the division by the array size is used as index. The second element of MyArray<int, 4> could be accessed using indices 1, 5, 9, 4449, ect.

Related

Is there a way to merge / concatenate precompiler lists with C++ macros?

I have two lists:
#define LIST1 {1, 2, 3}
#define LIST2 {4, 5, 6}
and using C++ macros I would like to write something like this:
// Obviously doesn't work
#define MERGE LIST1 ## LIST2
int my_array[] = MERGE;
to yield:
int my_array[] = {1, 2, 3, 4, 5, 6};
during compile-time.
Is something like this possible? There are other questions concerning this with strings, however I can't figure out for the life of me how to do this with non-string array declarations.
Edit:
I certainly would prefer to not use macros, and would prefer that the list format be different as well. Unfortunately, the header file that contains these list definitions isn’t a file that I can edit.
Don't use macros unless there is no other option, prefer templates.
They are typesafe.
For example you can make a compile time evaluated function (constexpr)
that merges two lists (arrays) and returns an array.
#include <array>
// type_t is the type held by the array (an int in this example)
// N = size of first array
// M = size of second array
// const type_t(&arr)[N] is the syntax for passing an array by const reference
template<typename type_t, std::size_t N, std::size_t M>
constexpr auto merge(const type_t(&arr1)[N], const type_t(&arr2)[M])
{
std::array<type_t, N + M> arr{}; // this initialization is needed in constexpr
std::size_t index{ 0 };
for (const auto& value : arr1) arr[index++] = value;
for (const auto& value : arr2) arr[index++] = value;
return arr;
}
int main()
{
constexpr auto arr = merge({ 1,2,3 }, { 4,5,6 });
constexpr auto strings = merge( {"abc", "def" }, {"ijk", "lmn"} );
// static_assert is like assert, but evaluated at compile time.
static_assert(arr.size() == 6);
static_assert(arr[4] == 5);
return 0;
}
It is easily achievable by slightly restating your code:
#define LIST1 1, 2, 3
#define LIST2 4, 5, 6
#define MERGE LIST1, LIST2
int my_array[] = { MERGE };
#include <iostream>
int main() {
for(auto const& x : my_array) {
std::cout << x << "\n";
}
}
Demo

std::vector.at(). Does it return a reference or a copy?

I've just started learning C++ and I'm trying how std::vector works.
I have this test program:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> element1 = { 1, 2,3 };
std::vector<int> element2 = { 4, 5, 6 };
std::vector<std::vector<int>> lista = { element1, element2 };
std::vector<int> var = lista.at(0);
for (std::vector<int>::const_iterator i = var.begin(); i != var.end(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
var[0] = 22;
for (std::vector<int>::const_iterator i = var.begin(); i != var.end(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
for (std::vector<int>::const_iterator i = lista.at(0).begin(); i != lista.at(0).end(); ++i)
std::cout << *i << ' ';
std::cout << std::endl;
return 0;
}
That outputs:
1 2 3
22 2 3
1 2 3
I think that at operator doesn't return a reference (but maybe I'm wrong), so I think it returns a new vector, isn't it?
But, if I want to get a reference, how can I do it?
UPDATE:
And... if I want to get in lista the references of element1 and element2 instead of a copy?
at returns a reference (and a const reference for the const version).
Your issue is that you are taking an explicit value copy in your code with std::vector<int> var = lista.at(0);. The obvious fix is auto& var = lista.at(0);.
Finally, if you wish to avoid a value copy of element1 and element2, you can remove them and write
std::vector<std::vector<int>> lista = { { 1, 2,3 }, { 4, 5, 6 } };
instead.
Reference: http://en.cppreference.com/w/cpp/container/vector/at
at returns a reference.
You store it in a copy here std::vector<int> var = lista.at(0);
You might do std::vector<int>& var = lista.at(0); to get reference.
I think that at operator doesn't return a reference (but maybe I'm wrong)
You're wrong indeed. vector::at returns a reference, as shown in the declaration:
reference at( size_type pos );
const_reference at( size_type pos ) const;
However, std::vector<int> var is not a reference, and you copy initialize it from the returned reference.
But, if I want to get a reference, how can I do it?
To get a reference, you need a reference variable where you can capture the reference returned by at:
std::vector<int>& var = lista.at(0);
// ^ a reference
And also here, std::vector<std::vector<int>> lista = { element1, element2 };, I think there is a copy of element1 and element2 in lista vector.
That's right.
If I don't want to create a copy of element1 and element2, what do I have to do?
If you don't want to store (copies of) vectors in the outer vector, then you need to store something else. You cannot store references in containers, but you can store std::reference_wrappers or pointers. For example:
std::vector<std::vector<int>*> lista = { &element1, &element2 };
You can then get a reference to the pointed vector using the indirection operator.
It's not clear from your example what you're trying to do, perhaps it might make sense to have a vector of vectors, and let element1 and element2 be references instead:
std::vector<std::vector<int>> lista = {
{ 1, 2, 3 },
{ 4, 5, 6 },
};
std::vector<int>& element1 = lista[0];
std::vector<int>& element2 = lista[1];
If you only want to avoid copying contents of the subvectors, and if you don't intend to use element1 and element2 afterwards, then there is another way: You can move construct the subvectors of lista:
std::vector<std::vector<int>> lista = {
std::move(element1),
std::move(element2),
};
// element1 and elemenet2 are now in an unspecified state
var is not a reference, its just another variable like b below.
int a = 5;
int b = a;
int &bref = a;
b=6;
cout<<a<<endl; // a is still 5
bref = 6;
cout<<a<<endl; // a is now 6
What you want is bref and not b ie
std::vector<int> &var = lista.at(0);

Sorting one std::vector based on the content of another [duplicate]

This question already has answers here:
How can I sort two vectors in the same way, with criteria that uses only one of the vectors?
(9 answers)
Closed 9 months ago.
I have several std::vector, all of the same length. I want to sort one of these vectors, and apply the same transformation to all of the other vectors. Is there a neat way of doing this? (preferably using the STL or Boost)? Some of the vectors hold ints and some of them std::strings.
Pseudo code:
std::vector<int> Index = { 3, 1, 2 };
std::vector<std::string> Values = { "Third", "First", "Second" };
Transformation = sort(Index);
Index is now { 1, 2, 3};
... magic happens as Transformation is applied to Values ...
Values are now { "First", "Second", "Third" };
friol's approach is good when coupled with yours. First, build a vector consisting of the numbers 1…n, along with the elements from the vector dictating the sorting order:
typedef vector<int>::const_iterator myiter;
vector<pair<size_t, myiter> > order(Index.size());
size_t n = 0;
for (myiter it = Index.begin(); it != Index.end(); ++it, ++n)
order[n] = make_pair(n, it);
Now you can sort this array using a custom sorter:
struct ordering {
bool operator ()(pair<size_t, myiter> const& a, pair<size_t, myiter> const& b) {
return *(a.second) < *(b.second);
}
};
sort(order.begin(), order.end(), ordering());
Now you've captured the order of rearrangement inside order (more precisely, in the first component of the items). You can now use this ordering to sort your other vectors. There's probably a very clever in-place variant running in the same time, but until someone else comes up with it, here's one variant that isn't in-place. It uses order as a look-up table for the new index of each element.
template <typename T>
vector<T> sort_from_ref(
vector<T> const& in,
vector<pair<size_t, myiter> > const& reference
) {
vector<T> ret(in.size());
size_t const size = in.size();
for (size_t i = 0; i < size; ++i)
ret[i] = in[reference[i].first];
return ret;
}
typedef std::vector<int> int_vec_t;
typedef std::vector<std::string> str_vec_t;
typedef std::vector<size_t> index_vec_t;
class SequenceGen {
public:
SequenceGen (int start = 0) : current(start) { }
int operator() () { return current++; }
private:
int current;
};
class Comp{
int_vec_t& _v;
public:
Comp(int_vec_t& v) : _v(v) {}
bool operator()(size_t i, size_t j){
return _v[i] < _v[j];
}
};
index_vec_t indices(3);
std::generate(indices.begin(), indices.end(), SequenceGen(0));
//indices are {0, 1, 2}
int_vec_t Index = { 3, 1, 2 };
str_vec_t Values = { "Third", "First", "Second" };
std::sort(indices.begin(), indices.end(), Comp(Index));
//now indices are {1,2,0}
Now you can use the "indices" vector to index into "Values" vector.
Put your values in a Boost Multi-Index container then iterate over to read the values in the order you want. You can even copy them to another vector if you want to.
Only one rough solution comes to my mind: create a vector that is the sum of all other vectors (a vector of structures, like {3,Third,...},{1,First,...}) then sort this vector by the first field, and then split the structures again.
Probably there is a better solution inside Boost or using the standard library.
You can probably define a custom "facade" iterator that does what you need here. It would store iterators to all your vectors or alternatively derive the iterators for all but the first vector from the offset of the first. The tricky part is what that iterator dereferences to: think of something like boost::tuple and make clever use of boost::tie. (If you wanna extend on this idea, you can build these iterator types recursively using templates but you probably never want to write down the type of that - so you either need c++0x auto or a wrapper function for sort that takes ranges)
I think what you really need (but correct me if I'm wrong) is a way to access elements of a container in some order.
Rather than rearranging my original collection, I would borrow a concept from Database design: keep an index, ordered by a certain criterion. This index is an extra indirection that offers great flexibility.
This way it is possible to generate multiple indices according to different members of a class.
using namespace std;
template< typename Iterator, typename Comparator >
struct Index {
vector<Iterator> v;
Index( Iterator from, Iterator end, Comparator& c ){
v.reserve( std::distance(from,end) );
for( ; from != end; ++from ){
v.push_back(from); // no deref!
}
sort( v.begin(), v.end(), c );
}
};
template< typename Iterator, typename Comparator >
Index<Iterator,Comparator> index ( Iterator from, Iterator end, Comparator& c ){
return Index<Iterator,Comparator>(from,end,c);
}
struct mytype {
string name;
double number;
};
template< typename Iter >
struct NameLess : public binary_function<Iter, Iter, bool> {
bool operator()( const Iter& t1, const Iter& t2 ) const { return t1->name < t2->name; }
};
template< typename Iter >
struct NumLess : public binary_function<Iter, Iter, bool> {
bool operator()( const Iter& t1, const Iter& t2 ) const { return t1->number < t2->number; }
};
void indices() {
mytype v[] = { { "me" , 0.0 }
, { "you" , 1.0 }
, { "them" , -1.0 }
};
mytype* vend = v + _countof(v);
Index<mytype*, NameLess<mytype*> > byname( v, vend, NameLess<mytype*>() );
Index<mytype*, NumLess <mytype*> > bynum ( v, vend, NumLess <mytype*>() );
assert( byname.v[0] == v+0 );
assert( byname.v[1] == v+2 );
assert( byname.v[2] == v+1 );
assert( bynum.v[0] == v+2 );
assert( bynum.v[1] == v+0 );
assert( bynum.v[2] == v+1 );
}
A slightly more compact variant of xtofl's answer for if you are just looking to iterate through all your vectors based on the of a single keys vector. Create a permutation vector and use this to index into your other vectors.
#include <boost/iterator/counting_iterator.hpp>
#include <vector>
#include <algorithm>
std::vector<double> keys = ...
std::vector<double> values = ...
std::vector<size_t> indices(boost::counting_iterator<size_t>(0u), boost::counting_iterator<size_t>(keys.size()));
std::sort(begin(indices), end(indices), [&](size_t lhs, size_t rhs) {
return keys[lhs] < keys[rhs];
});
// Now to iterate through the values array.
for (size_t i: indices)
{
std::cout << values[i] << std::endl;
}
ltjax's answer is a great approach - which is actually implemented in boost's zip_iterator http://www.boost.org/doc/libs/1_43_0/libs/iterator/doc/zip_iterator.html
It packages together into a tuple whatever iterators you provide it.
You can then create your own comparison function for a sort based on any combination of iterator values in your tuple. For this question, it would just be the first iterator in your tuple.
A nice feature of this approach is that it allows you to keep the memory of each individual vector contiguous (if you're using vectors and that's what you want). You also don't need to store a separate index vector of ints.
This would have been an addendum to Konrad's answer as it an approach for a in-place variant of applying the sort order to a vector. Anyhow since the edit won't go through I will put it here
Here is a in-place variant with a slightly higher time complexity that is due to a primitive operation of checking a boolean. The additional space complexity is of a vector which can be a space efficient compiler dependent implementation. The complexity of a vector can be eliminated if the given order itself can be modified.
Here is a in-place variant with a slightly higher time complexity that is due to a primitive operation of checking a boolean. The additional space complexity is of a vector which can be a space efficient compiler dependent implementation. The complexity of a vector can be eliminated if the given order itself can be modified. This is a example of what the algorithm is doing.
If the order is 3 0 4 1 2, the movement of the elements as indicated by the position indices would be 3--->0; 0--->1; 1--->3; 2--->4; 4--->2.
template<typename T>
struct applyOrderinPlace
{
void operator()(const vector<size_t>& order, vector<T>& vectoOrder)
{
vector<bool> indicator(order.size(),0);
size_t start = 0, cur = 0, next = order[cur];
size_t indx = 0;
T tmp;
while(indx < order.size())
{
//find unprocessed index
if(indicator[indx])
{
++indx;
continue;
}
start = indx;
cur = start;
next = order[cur];
tmp = vectoOrder[start];
while(next != start)
{
vectoOrder[cur] = vectoOrder[next];
indicator[cur] = true;
cur = next;
next = order[next];
}
vectoOrder[cur] = tmp;
indicator[cur] = true;
}
}
};
Here is a relatively simple implementation using index mapping between the ordered and unordered names that will be used to match the ages to the ordered names:
void ordered_pairs()
{
std::vector<std::string> names;
std::vector<int> ages;
// read input and populate the vectors
populate(names, ages);
// print input
print(names, ages);
// sort pairs
std::vector<std::string> sortedNames(names);
std::sort(sortedNames.begin(), sortedNames.end());
std::vector<int> indexMap;
for(unsigned int i = 0; i < sortedNames.size(); ++i)
{
for (unsigned int j = 0; j < names.size(); ++j)
{
if (sortedNames[i] == names[j])
{
indexMap.push_back(j);
break;
}
}
}
// use the index mapping to match the ages to the names
std::vector<int> sortedAges;
for(size_t i = 0; i < indexMap.size(); ++i)
{
sortedAges.push_back(ages[indexMap[i]]);
}
std::cout << "Ordered pairs:\n";
print(sortedNames, sortedAges);
}
For the sake of completeness, here are the functions populate() and print():
void populate(std::vector<std::string>& n, std::vector<int>& a)
{
std::string prompt("Type name and age, separated by white space; 'q' to exit.\n>>");
std::string sentinel = "q";
while (true)
{
// read input
std::cout << prompt;
std::string input;
getline(std::cin, input);
// exit input loop
if (input == sentinel)
{
break;
}
std::stringstream ss(input);
// extract input
std::string name;
int age;
if (ss >> name >> age)
{
n.push_back(name);
a.push_back(age);
}
else
{
std::cout <<"Wrong input format!\n";
}
}
}
and:
void print(const std::vector<std::string>& n, const std::vector<int>& a)
{
if (n.size() != a.size())
{
std::cerr <<"Different number of names and ages!\n";
return;
}
for (unsigned int i = 0; i < n.size(); ++i)
{
std::cout <<'(' << n[i] << ", " << a[i] << ')' << "\n";
}
}
And finally, main() becomes:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
void ordered_pairs();
void populate(std::vector<std::string>&, std::vector<int>&);
void print(const std::vector<std::string>&, const std::vector<int>&);
//=======================================================================
int main()
{
std::cout << "\t\tSimple name - age sorting.\n";
ordered_pairs();
}
//=======================================================================
// Function Definitions...
**// C++ program to demonstrate sorting in vector
// of pair according to 2nd element of pair
#include <iostream>
#include<string>
#include<vector>
#include <algorithm>
using namespace std;
// Driver function to sort the vector elements
// by second element of pairs
bool sortbysec(const pair<char,char> &a,
const pair<int,int> &b)
{
return (a.second < b.second);
}
int main()
{
// declaring vector of pairs
vector< pair <char, int> > vect;
// Initialising 1st and 2nd element of pairs
// with array values
//int arr[] = {10, 20, 5, 40 };
//int arr1[] = {30, 60, 20, 50};
char arr[] = { ' a', 'b', 'c' };
int arr1[] = { 4, 7, 1 };
int n = sizeof(arr)/sizeof(arr[0]);
// Entering values in vector of pairs
for (int i=0; i<n; i++)
vect.push_back( make_pair(arr[i],arr1[i]) );
// Printing the original vector(before sort())
cout << "The vector before sort operation is:\n" ;
for (int i=0; i<n; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
// Using sort() function to sort by 2nd element
// of pair
sort(vect.begin(), vect.end(), sortbysec);
// Printing the sorted vector(after using sort())
cout << "The vector after sort operation is:\n" ;
for (int i=0; i<n; i++)
{
// "first" and "second" are used to access
// 1st and 2nd element of pair respectively
cout << vect[i].first << " "
<< vect[i].second << endl;
}
getchar();
return 0;`enter code here`
}**
with C++11 lambdas and the STL algorithms based on answers from Konrad Rudolph and Gabriele D'Antona:
template< typename T, typename U >
std::vector<T> sortVecAByVecB( std::vector<T> & a, std::vector<U> & b ){
// zip the two vectors (A,B)
std::vector<std::pair<T,U>> zipped(a.size());
for( size_t i = 0; i < a.size(); i++ ) zipped[i] = std::make_pair( a[i], b[i] );
// sort according to B
std::sort(zipped.begin(), zipped.end(), []( auto & lop, auto & rop ) { return lop.second < rop.second; });
// extract sorted A
std::vector<T> sorted;
std::transform(zipped.begin(), zipped.end(), std::back_inserter(sorted), []( auto & pair ){ return pair.first; });
return sorted;
}
So many asked this question and nobody came up with a satisfactory answer. Here is a std::sort helper that enables to sort two vectors simultaneously, taking into account the values of only one vector. This solution is based on a custom RadomIt (random iterator), and operates directly on the original vector data, without temporary copies, structure rearrangement or additional indices:
C++, Sort One Vector Based On Another One

How to avoid de-reference overhead of pointers, using references in containers?

I'm encountering a design challenge. There is a huge std::vector<int> called O say of size 10000. There are two many objects of type Foo, f_1...f_n. Each Foo has an internal std::vector<int> which is a suborder of O. For example:
O = 1, 2, ..., 100000
f_1.order = 1, 2, 3
f_2.order = 1, 4, 16
f_3.order = 100, 101, 102
// ...
The main requirement is to update corresponding values of O when a f_n changes its values. Length and contents of all Foo objects are knows at construction time and not supposed to change during their lifetime. For example it's known that f_1 holds first, second and third elements of O.
The obvious solution is to use pointers of course. Foo may hold a std::vector<int*> which each element points to underlying data of original order (O).
On the other hand, my program do some heavy calculations using Foo objects. So I'm looking for a method to remove overhead of pointer dereferencing. It would be nice if design allow me to use some sort of std::vector<int&> but it's not possible (I guess because vector<T> needs presence of T*).
A colleague suggested to use boost::ptr_vector. Another suggested holding indexes in a vector<size_t>...
I would say that optimizing for pointer dereferencing overhead is pointless. Let's look at some example code:
void bar(int i);
void foo(int* p, int i)
{
bar(*p);
bar(i);
}
And now let's look at the assembly of it:
void foo(int* p, int i)
{
push rbx
mov ebx, esi
bar(*p);
mov edi, DWORD PTR [rdi]
call a <foo+0xa>
bar(i);
mov edi, ebx
call 11 <foo+0x11>
}
There's an "overhead" of one memory read.
As for using references, it's not gonna do anything useful. References may have different semantics to pointers, but underneath, they're still pointers:
void foo(int& r)
{
bar(r);
mov edi,DWORD PTR [rbx]
call 20 <_Z3fooPiiRi+0x20>
}
There's the same memory read happening.
I'm not sure if this counts as an "answer", but seriously: don't bother.
This cannot be stressed enough - do not optimize your code before you know you have a problem. Pointer dereferencing is not costly, and is usually not the main bottleneck in a program.
Note that references are implemented using pointer dereferencing, so even if you could do std::vector<int&>, it would not help.
If you really, really feel you must do something - even though I'm really, totally sure it can't possibly help your performance in any meaningful sense - you could try overlaying the memory. That is, you could define it like this (note that I'm not in any way endorsing this - I'm only pointing it out so that you don't do something worse):
std::vector<int> O;
struct Foo {
int *myData;
int &operator[](int offset) { return myData[offset]; }
};
O.resize(1000000, 0);
Foo f_1, f_2, ...;
f_1.myData = &(O[0]);
f_2.myData = &(O[3]);
O[0] = 5;
cout << f_1[0]; // prints 5
Also, BTW - please, please, please, do not use the name O as a variable. Please. It looks like a zero.
It sound as premature optimization. Dereference a pointer is ridiculously cheap.
The obvious solution is to use pointers of course. Foo may hold a std::vector which each element points to underlying data of original order (O).
Here a solution, deducting what you need, not using pointers, using std::reference_wrapper and std::ref:
struct Foo
{
Foo(std::vector<int>& _data) : dataFull(_data)
{ ; }
void add(int index)
{
assert(index < dataFull.size());
if(index < references.size())
{
// replace
references[index] = std::ref(dataFull[index]);
}
else
{
// add n times, need sync with index
while(index >= references.size())
{
references.push_back(std::ref(dataFull[index]));
}
}
// mark as valid index
indexes.push_back(index);
// sort for can find with binary_search
std::sort(indexes.begin(), indexes.end());
}
int* get(int index)
{
if(std::binary_search(indexes.begin(), indexes.end(), index))
{
return &references[index].get();
}
else
{
return NULL;
}
}
protected:
std::vector<int>& dataFull;
std::vector<std::reference_wrapper<int> > references;
std::vector<int> indexes;
};
int main()
{
const int size = 1000000;
std::vector<int> O;
O.resize(1000000, 0);
Foo f_1(O);
f_1.add(1);
f_1.add(2);
f_1.add(3);
Foo f_2(O);
f_2.add(1);
f_2.add(4);
f_2.add(16);
Foo f_3(O);
f_3.add(100);
f_3.add(101);
f_3.add(102);
// index 1 is changed, it must affect to all "Foo" that use this index (f_1 and f_2)
O[1] = 666;
// checking if it changed
assert( *f_1.get(1) == 666 );
assert( *f_2.get(1) == 666 );
assert( f_3.get(1) == NULL );
return 0;
}
EDIT:
Performance is same that if you use pointer, but std::reference_wrapper can be integrated best in templated code because you have T& and don't need have code for T* and T&.
Have indexes in other vector, only is useful if your struct is ordered by multiple criteria.
I show a example with a vector, where T is a struct complex with two fields. I can reorder this vector with 2 criterias, without touch the original.
template <typename T>
struct Index
{
typedef typename bool(*Comparator)(const T&, const T&);
Index(std::vector<T>& _data, Comparator _comp)
: dataFull(_data)
, comp(_comp)
{
for(unsigned int i = 0; i < dataFull.size(); ++i)
{
add(i);
}
commit();
}
void commit()
{
std::sort(references.begin(), references.end(), comp);
}
std::vector<std::reference_wrapper<T> >& getReference() {return references;}
protected:
void add(int index)
{
assert(index < dataFull.size());
references.push_back(std::ref(dataFull[index]));
}
protected:
std::vector<T>& dataFull;
std::vector<std::reference_wrapper<T> > references;
Comparator comp;
};
int main()
{
struct ComplexData
{
int field1;
int field2;
};
// Generate vector
const int size = 10;
std::vector<ComplexData> data;
data.resize(size);
for(unsigned int i = 0; i < size; ++i)
{
ComplexData& c = data[i];
c.field1 = i;
c.field2 = size - i;
}
// Vector reordered without touch original
std::cout << "Vector data, ordered by field1" << std::endl;
{
Index<ComplexData> f_1(data,
[](const ComplexData& a, const ComplexData& b){return a.field1 < b.field1;});
auto it = f_1.getReference().begin();
auto ite = f_1.getReference().end();
for(; it != ite; ++it)
{
std::cout << "-> " << it->get().field1 << " - " << it->get().field2 << std::endl;
}
}
// Vector reordered without touch original
std::cout << "Vector data, ordered by field2" << std::endl;
{
Index<ComplexData> f_2(data,
[](const ComplexData& a, const ComplexData& b){return a.field2 < b.field2;});
auto it = f_2.getReference().begin();
auto ite = f_2.getReference().end();
for(; it != ite; ++it)
{
std::cout << "-> " << it->get().field1 << " - " << it->get().field2 << std::endl;
}
}
return 0;
}

How can I fill a map of int and vector<int> in C++?

I have been working with <map>, where I declared a map as follows:
map <int, vector<int> > tree;
I am now trying to assign values to it. My goal is to place multiple values as elements of its keys. Something like this:
0=null
1=>0
2=>1,0
3=>2,1,0
4=>3,2,1,0
5=>0
I tried to assign to the map like this, but it does not work:
tree[3]=vector<int>(2,1,0);
However, the following two ways of assigning work:
tree[1]=vector<int>(0);
tree[2]=vector<int>(1,0);
Where is the problem? How can I make a function that works as a Python dictionary?
I am not using C++11.
With C++11, you could try:
tree[3]=vector<int>({2,1,0});
Other than that, the question could use more details and some code of what you already tried...
Since you are asking for a C++03 answer, this (more verbose than C++11) solution will work.
tree[3].push_back(2);
tree[3].push_back(1);
tree[3].push_back(0);
Please note that the following two lines are not doing what you expect:
tree[1] = vector<int>(0);
tree[2] = vector<int>(1, 0);
The first parameter of the corresponding vector's constructor is the initial size of the container. The second parameter is the value to initialize elements of the container with. So, the first line constructs an empty vector and the second line constructs a vector with one element which is initialized to 0.
As indicated by the other answers, push_back() is a good option if you cannot use C++11 features. However, once you upgrade to C++11, you can also initialize your map by using nested list initialization as follows:
int main() {
std::map<int, std::vector<int>> tree{
{1, {0}}, {2, {1, 0}}, {3, {2, 1, 0}}, {4, { 3, 2, 1, 0 }}, {5, { 0 }}
};
for (auto const &kv : tree) {
std::cout << kv.first << " =>";
for (auto const &i : kv.second)
std::cout << " " << i;
std::cout << std::endl;
}
return 0;
}
Output:
1 => 0
2 => 1 0
3 => 2 1 0
4 => 3 2 1 0
5 => 0
Code on Ideone
Without C++11, the code won't be as elegant:
tree[0]; // create empty vector for index 0
tree[1].push_back(0);
tree[2].push_back(1);
tree[2].push_back(0);
tree[3].push_back(2);
tree[3].push_back(1);
tree[3].push_back(0);
tree[4].push_back(3);
tree[4].push_back(2);
tree[4].push_back(1);
tree[4].push_back(0);
tree[5].push_back(0);
Have you considered std::multi_map?
#include <map>
int main()
{
std::multimap<int, int> map;
for (int i=1; i < 6; i++)
for (int j=1; j < i; j++)
map.insert(std::make_pair(i, j));
}
As Daniel Frey points out, you can use
tree[3] = vector<int>({2,1,0})
In python-like pseudo-code, the vector constructor being used here is
def vector(arr)
The original post suggests you're trying to use a constructor of the form
def vector(*args)
which doesn't exist.
If you're not using C++11, consider using one of vector's other constructors.
I don't particularly like va_args but the solution is "neater" to a degree than most as long as you (the user) don't mess it up, i.e. mixing types. Another downside is that your vector cannot contain -1, but your example case doesn't show it.
#include <vector>
#include <cstdarg>
#include <iostream>
//Unsafe but it works.
template<typename T>
std::vector<T> make_vector(T num, ...) {
std::vector<T> result;
va_list args;
va_start(args,num);
for(T i = num; i != -1; i = va_arg(args,T))
result.push_back(i);
va_end(args);
return result;
}
int main() {
std::vector<int> v = make_vector(0,1,2,3,-1); //-1 to stop
//do stuff with vector v
}