Simpler way to set multiple array slots to one value
Solution 1
This function will help make it less painful.
void initialize(int * arr, std::initializer_list<std::size_t> list, int value) {
for (auto i : list) {
arr[i] = value;
}
}
Call it like this.
initialize(array,{9,5,14},2);
Solution 2
A variant of aaronman's answer:
template <typename T>
void initialize(T array[], const T& value)
{
}
template <size_t index, size_t... indices, typename T>
void initialize(T array[], const T& value)
{
array[index] = value;
initialize<indices...>(array, value);
}
int main()
{
int array[10];
initialize<0,3,6>(array, 99);
std::cout << array[0] << " " << array[3] << " " << array[6] << std::endl;
}
Example: Click here
Solution 3
Just for the fun of it I created a somewhat different approach which needs a bit of infrastructure allowing initialization like so:
double array[40] = {};
"9 5 14"_idx(array) = 1;
"8 15 23 12"_idx(array) = 2;
If the digits need to be separated by commas, there is a small change needed. In any case, here is the complete code:
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iterator>
template <int Size, typename T = int>
class assign
{
int d_indices[Size];
int* d_end;
T* d_array;
void operator=(assign const&) = delete;
public:
assign(char const* base, std::size_t n)
: d_end(std::copy(std::istream_iterator<int>(
std::istringstream(std::string(base, n)) >> std::skipws),
std::istream_iterator<int>(), this->d_indices))
, d_array()
{
}
assign(assign<Size>* as, T* a)
: d_end(std::copy(as->begin(), as->end(), this->d_indices))
, d_array(a) {
}
assign(assign const& o)
: d_end(std::copy(o.begin(), o.end(), this->d_indices))
, d_array(o.d_array)
{
}
int const* begin() const { return this->d_indices; }
int const* end() const { return this->d_end; }
template <typename A>
assign<Size, A> operator()(A* array) {
return assign<Size, A>(this, array);
}
void operator=(T const& value) {
for (auto it(this->begin()), end(this->end()); it != end; ++it) {
d_array[*it] = value;
}
}
};
assign<30> operator""_idx(char const* base, std::size_t n)
{
return assign<30>(base, n);
}
int main()
{
double array[40] = {};
"1 3 5"_idx(array) = 17;
"4 18 7"_idx(array) = 19;
std::copy(std::begin(array), std::end(array),
std::ostream_iterator<double>(std::cout, " "));
std::cout << "\n";
}
Solution 4
I just had a play around for the sake of fun / experimentation (Note my concerns at the bottom of the answer):
It's used like this:
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
Source code:
#include <assert.h> //Needed to test variables
#include <iostream>
#include <cstddef>
template <class ArrayPtr, class Value>
class SmartAssign
{
ArrayPtr m_array;
public:
class Proxy
{
ArrayPtr m_array;
size_t m_index;
Proxy* m_prev;
Proxy(ArrayPtr array, size_t index)
: m_array(array)
, m_index(index)
, m_prev(nullptr)
{ }
Proxy(Proxy* prev, size_t index)
: m_array(prev->m_array)
, m_index(index)
, m_prev(prev)
{ }
void assign(Value value)
{
m_array[m_index] = value;
for (auto prev = m_prev; prev; prev = prev->m_prev) {
m_array[prev->m_index] = value;
}
}
public:
void operator=(Value value)
{
assign(value);
}
Proxy operator[](size_t index)
{
return Proxy{this, index};
}
friend class SmartAssign;
};
SmartAssign(ArrayPtr array)
: m_array(array)
{
}
Proxy operator[](size_t index)
{
return Proxy{m_array, index};
}
};
template <class T>
SmartAssign<T*, T> smartAssign(T* array)
{
return SmartAssign<T*, T>(array);
}
int main()
{
int array[10];
smartAssign(array)[0][8] = 1;
smartAssign(array)[1][4][2] = 2;
smartAssign(array)[3] = 3;
smartAssign(array)[5][9][6][7] = 4;
for (auto i : array) {
std::cout << i << "\n";
}
//Now to test the variables
assert(array[0] == 1 && array[8] == 1);
assert(array[1] == 2 && array[4] == 2 && array[2] == 2);
assert(array[3] == 3);
assert(array[5] == 4 && array[9] == 4 && array[6] == 4 && array[7] == 4);
}
Let me know what you think, I don't typically write much code like this, I'm sure someone will point out some problems somewhere ;)
I'm not a 100% certain of the lifetime of the proxy objects.
Solution 5
The best you can do if your indexes are unrelated is "chaining" the assignments:
array[9] = array[5] = array[14] = 1;
However if you have some way to compute your indexes in a deterministic way you could use a loop:
for (size_t i = 0; i < 3; ++i)
array[transform_into_index(i)] = 1;
This last example also obviously applies if you have some container where your indexes are stored. So you could well do something like this:
const std::vector<size_t> indexes = { 9, 5, 14 };
for (auto i: indexes)
array[i] = 1;
Related videos on Youtube
Matthew D. Scholefield
I'm a passionate open source developer. Whenever I find something I don't understand, I rebuild it. Aside from programming, I occasionally do 3D graphics (With Blender), and a little music composition.
Updated on June 14, 2022Comments
-
Matthew D. Scholefield almost 2 years
I'm coding in C++, and I have the following code:
int array[30]; array[9] = 1; array[5] = 1; array[14] = 1; array[8] = 2; array[15] = 2; array[23] = 2; array[12] = 2; //...
Is there a way to initialize the array similar to the following?
int array[30]; array[9,5,14] = 1; array[8,15,23,12] = 2; //...
Note: In the actual code, there can be up to 30 slots that need to be set to one value.
-
aaronman over 10 yearsif they aren't contiguous it doesn't get much better than this, you could write a function that takes the array and the indicies
-
chris over 10 yearsThere's a GCC extension for this I think. Other than that, there's always
array[9] = array[5] = array[14] = 1;
I guess. -
RamonBoza over 10 yearsyou can also do
int number[3] = { 5, 7, 2 };
-
-
Tommy over 10 yearsWith only 30 values, I'm not sure if the overhead of calling a function transform_into_index() is worth a few less lines of code. Performance hit for nothing.
-
aschepler over 10 yearsWas about to post pretty much the same thing (but with templates).
-
aschepler over 10 yearsIn C++, a function call is often not a performance hit at all. Also, premature optimization is the root of all evil.
-
syam over 10 years@Tommy I for one am not sure the performance hit is a reason enough to write less readable code, especially since the function might well be inlined (and thus the call costs nothing ; the loop may in fact be unrolled and all indexes computed at compile-time, think
constexpr
). -
aaronman over 10 years@aschepler too often SO is about typing speed (though I actually really suck at typing :) )
-
Tommy over 10 yearsBut the code is not unreadable. Perhaps sorting the statements so that array[1] =, array[2]=... this is called loop unrolling and has advantages. Simple > Complicated. I stress again that if there were 300 values or something, then a loop would most definitely be needed.
-
Matthew D. Scholefield over 10 yearsThis seems like it would be simpler, except sadly, the compiler I'm using gives me the error:
sorry, unimplemented: non-trivial designated initializers not supported
. -
syam over 10 years@Tommy Well, "unreadable" is a matter of opinion. Repeating the same variable name 30 times is definitely unreadable (rather unmaintainable, actually) in my book.
-
Matthew D. Scholefield over 10 yearsYes, like you mentioned, I am doing this for readiblity/simplicity, rather than for efficiency.
-
aschepler over 10 yearsNot that it's a competition or anything.
-
Tommy over 10 yearsFrom reading the values op posted, there does not appear to be any easy pattern of the indices ( I tried to find a simple transformation), which is why I suspect a performance hit because transform_into_index() is going to be complicated. Or impossible =).
-
Matthew D. Scholefield over 10 yearsThis is exactly what I need, just when I compile, I get the error:
error: 'std::initializer_list' has not been declared
along with syntax errors due to that. Any ideas? -
aaronman over 10 years@RandomPerson323 do you have the
-std=c++11
flag, what compiler are you using -
aschepler over 10 yearsAnd be sure to
#include <initializer_list>
. (My demo: coliru.stacked-crooked.com/a/9e7e4ed2354a9714 ) -
Matthew D. Scholefield over 10 yearsI did not set any flag (do you mean in the makefile?), and I am compiling for the nds with devkitPro. When I added the include, the error changed:
-
Matthew D. Scholefield over 10 yearsNow I get syntax errors. This is the first one:
error: expected constructor, destructor, or type conversion before '(' token
-
aaronman over 10 years@RandomPerson323 I'm not familiar with devkitpro, but it says right there you need
-std=c++11
for this to work it sounds like your compilers out of date since all the good compilers have full c++11 support -
aaronman over 10 years@RandomPerson323 it would be helpful if you edited your question to include exactly what you have, my code compiles fine
-
Matthew D. Scholefield over 10 yearsI added the flag, and fixed a stupid error I accidentally had, and now it compiles :).
-
aaronman over 10 years@RandomPerson323 nice, if possible I recommend you update your compiler to a current one with full c++11 support
-
Matthew D. Scholefield over 10 years
-
Matthew D. Scholefield over 10 yearsAlthough this would not be as readably, it would definitely save space.
-
aaronman over 10 yearsThis is slightly disturbing +1
-
Matthew D. Scholefield over 10 yearsLol, yes, this it crazy. One question: Would this be more efficient (At running the program, not typing), and if so, by how much?
-
goji over 10 years@Dietmar Kühl Interesting. I must play around with the literal operator sometime. Can you see any problems with my answer?
-
goji over 10 yearsI like this one best for simplicity, altho coding mine was fun ;)
-
PaperBirdMaster over 10 yearsI liked this one! (though i hate
va_lists
) but i've tested the code on ideone ( ideone.com/tCma9B ) and doesn't works: it doesn't initialize the first index passed on selection. -
Abhijit over 10 years@PaperBirdMaster: The first index is the length rather than the Index, so it will not be initialized. As you might recollect, the way argument passing works, there should be someway for the recipient to know what is the data type and no of data passed. The first number in the list actually does it.
-
Abhijit over 10 years@PaperBirdMaster: I understand your predicament in using
va_list
, but unless we have something betterinitialization list
orvariadic template
, that is the only viable approach. -
PaperBirdMaster over 10 yearsoh! first number is the lenght, sorry for the misunderstanding :O
-
Matthew D. Scholefield over 10 yearsAlthough this would be slightly less readable (because of the underscore syntax), how wold it compare speed-wise to aarman's answer?
-
Matthew D. Scholefield over 10 yearsSo, is
std::valarray<int> array(30);
to create the array? -
Abhijit over 10 years@RandomPerson323: Yes, that will create an array of 30 integers
-
Matthew D. Scholefield over 10 yearsOK, when I get the time I will look into this.
-
Abhijit over 10 years@PaperBirdMaster: I have modified the code, to remove the dependency on the length argument
-
Abhijit over 10 years@RandomPerson323: And my guess is, this solution would be comparable in terms of efficiency to the already posted once.
-
Khurshid Normuradov over 10 yearsI agree about less readable. aarman's answer is good, but it can't check array bound. My implement can't check array bound,too, but it can give warning at compile time.
-
KitsuneYMG over 10 yearsI like this one the best. Due to the way template expansion works, it's closest to the 'manual' way. Since it's all compiler time indexing, there is even the possibility of
memset
being used for larger contiguous chunks of identical values. -
Dietmar Kühl over 10 years@RandomPerson323: The implementation in the answer uses a fairly heavy-weight run-time approach to parsing the string. It could be done at compile-time, emitting constant expression, I think but it wouldn't necessarily be faster. Personally, I'm not quite satisfied with the notation and my main reason for posting it was to show an alternative which may lead to something useful.