too many initializers for array in struct - c++

I have:
struct X {
int i, j;
};
struct XArray {
X xs[3];
};
X xs1[3] { {1, 2}, {3, 4}, {5, 6} };
XArray xs2 { {1, 2}, {3, 4}, {5, 6} };
The xs1 initializes fine, initializing xs2 gives compiler error:
error: too many initializers for 'XArray'
XArray xs2 { {1, 2}, {3, 4}, {5, 6} };
^
What is wrong? Why can't I initialize?

You need another level of curly-braces:
XArray xs2 { { {1, 2}, {3, 4}, {5, 6} } };
// ^ ^ ^
// | | |
// For XArray structure | |
// | |
// For xs array |
// |
// For the X structure

The compileŕ assumes that xs is one field, the array will only be resolved when you add another brace like:
XArray xs2 { {{1, 2}, {3, 4}, {5, 6}} };
When you would add another element, e.g.
struct YArray {
X a;
X xs[3];
}
then it becomes clear that a and xs both need to be put into braces:
YArray y{
{1,2}, // a
{ {1, 2}, {3, 4}, {5, 6} } // xs
};

X xs[3] = { {1,2}, {3,4}, {5,6}};
Then you plug the whole part to the right into your code:
XArray x2 = { { {1,2}, ... {5,6} }};
This is because XArray has only one member, and it needs one pair of brackets enclosing it:
XArray t = { /* value */ };
And value happens to be an array, which also needs brackets:
X xs[3] = { /* value2 */ };
Since this array holds three values, each of them has to be initialized with a pair of numbers.

You have to use:
XArray xs2 { { {1, 2}, {3, 4}, {5, 6} } };
This way the first element of XArray is initialized with: { {1, 2}, {3, 4}, {5, 6} }.
Online here

Related

Lexicographic Rank of a Set Partitioned Into Groups

Given a set of 8 sequential numbers {0..7} partitioned into 4 groups of size 2, with the numbers in each group in ascending order, how can a rank be generated for the set? The rank should be in lexicographic order, and preferably the algorithm should be linear in complexity.
Examples of the partitioning:
{{0 1} {2 3} {4 5} {6 7}} // Rank 0
...
{{6 7} {4 5} {2 3} {0 1}} // Rank 2519
Because the numbers in each group are in ascending order, the groups are effectively treated like combinations, not permutations, so a group containing e.g. {5 4} will never occur.
How can this set of numbers be ranked sequentially in the range [0, 2520) (8C2 * 6C2 * 4C2)?
At present I compute the rank of each group as an 8C2 combination, then combine each rank together by treating it as a base-28 number. This obviously leaves gaps in the ranking, which is undesirable in my case. But, for what it's worth, here is how I'm currently ranking.
#include <array>
using std::array;
#include <cstdint>
#include <cstddef>
#include <iostream>
using std::cout;
using std::endl;
// Calculates n!.
uint32_t factorial(uint32_t n)
{
return n <= 1 ? 1 : n * factorial(n - 1);
}
// Calculate nCk: n!/((n-k)!*k!).
uint32_t choose(uint32_t n, uint32_t k)
{
return (n < k)
? 0
: factorial(n) / (factorial(n - k) * factorial(k));
}
template<size_t N, size_t K>
class CombinationRanker
{
array<array<uint32_t, K+1>, N+1> choices;
public:
/**
* Initialize a precomputed array of nCk (N and K inclusive).
*/
CombinationRanker()
{
for (unsigned n = 0; n <= N; ++n)
for (unsigned k = 0; k <= K; ++k)
this->choices[n][k] = choose(n, k);
}
/**
* Get the rank of a combination.
* #param comb A combination array of size K in ascending order.
*/
uint32_t rank(const array<uint8_t, K> comb) const
{
// Formula: (nCk) - ((n-c_1)Ck) - ((n-c_2)C(k-1)) - ... - ((n-c_k)C1)
// That assumes 1-based combinations with ranks starting at 1, so each
// element in the combination has 1 added to it, and the end result has 1
// subtracted from it to make the rank 0-based.
uint32_t rank = this->choices[N][K];
for (unsigned i = 0; i < K; ++i)
rank -= this->choices[N - (comb[i] + 1)][K - i];
return rank - 1;
}
};
int main(int argc, char* argv[])
{
CombinationRanker<8, 2> ranker;
array<array<uint8_t, 2>, 4> nums =
{{
{0, 1}, {2, 3}, {4, 5}, {6, 7}
}};
// Horribly sparse rank.
unsigned rank =
ranker.rank(nums[0]) * 28 * 28 * 28 +
ranker.rank(nums[1]) * 28 * 28 +
ranker.rank(nums[2]) * 28 +
ranker.rank(nums[3]);
cout << rank << endl; // 10835, but I want 0.
return 0;
}
I've tagged the post as C++ as that's the language I'm using; however, answers in another language are fine. It's more of a math question, but I'm looking for an answer that I can understand as a programmer, not a mathematician, and a code snippet would be helpful in that regard.
Here's what I came up with. It's quadratic in complexity, which is not the greatest, but it does the trick. The basic algorithm is as follows.
Given a set of sequential numbers from [0..7] partitioned into unordered pairs, loop over each pair and find its rank among pairs that
exclude numbers preceding it. Then multiplying each rank by its variable
base. The variable bases for each rank are 6C2*4C2*2C2, 4C2*2C2, and 2C2.
As an example, for {{2,3}, {6,7}, {4,5}, {0,1}}:
{2, 3} has rank 13.
{6, 7} has rank 14 among pairs excluding 2 and 3.
{4, 5} has rank 5 among pairs excluding 2, 3, 6, and 7.
{0, 1} is ignored.
Altogether, 13*6C2*4C2*2C2 + 14*4C2*2C2 + 5*2C2 = 1259
Other examples:
{{0, 1}, {2, 3}, {4, 5}, {6, 7}} -> 0
{{2, 3}, {6, 7}, {4, 5}, {0, 1}} -> 1259
{{2, 4}, {0, 1}, {3, 5}, {6, 7}} -> 1260
{{6, 7}, {4, 5}, {2, 3}, {0, 1}} -> 2519
Here's algorithm in code. I've hard coded quite a bit for brevity.
#include <iostream>
using std::cout;
using std::endl;
#include <array>
using std::array;
#include <cstdint>
typedef array<uint8_t, 2> pair_t;
/**
* #param set A set of 8 sequential numbers, [0..7], partitioned into unordered
* pairs.
*/
uint32_t rank(const array<pair_t, 4>& set) {
// All 28 (8C2) possible unordered subsets of the set of 8 sequential
// numbers, [0..7], in lexicographic order. Hard-coded here for brevity.
array<pair_t, 28> pairs = {{
{0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7},
{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7},
{2, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7},
{3, 4}, {3, 5}, {3, 6}, {3, 7},
{4, 5}, {4, 6}, {4, 7},
{5, 6}, {5, 7},
{6, 7},
}};
// Variable base for each rank "digit" (the base corresponding to the rank of
// each subset): 6C2*4C2*2C2, 4C2*2C2, 2C2. Again, hard-coded for brevity.
array<uint32_t, 3> bases = {{90, 6, 1}};
// Now rank the set.
uint32_t rank = 0;
// Rank among this many pairs. For N=8, 8C2->6C2->4C2->2C2 (28->15->6->1).
unsigned numRemaining = 28; // N*(N-1)/2
array<pair_t, 28> remaining = pairs;
// Loop over the first three unordered subsets. The last isn't needed for
// ranking--n from [0...(N-2)/2).
for (unsigned n = 0; n < 3; ++n)
{
unsigned remainingInd = 0;
const pair_t& sPair = set[n];
for (unsigned r = 0; r < numRemaining; ++r)
{
const pair_t& rPair = remaining[r];
if (sPair == rPair)
{
// Found the pair: rank it relative to the ramining pairs, and multiply
// it by the base for digit n.
rank += r * bases[n];
}
else if (
sPair[0] != rPair[0] && sPair[0] != rPair[1] &&
sPair[1] != rPair[0] && sPair[1] != rPair[1]
)
{
// The pair excludes the numbers in set[n], so keep it in the
// list of remaining pairs for the next digit's rank.
remaining[remainingInd++] = rPair;
}
}
// Number of remaining pairs.
numRemaining = remainingInd;
}
return rank;
}
int main(int argc, char* argv[])
{
// Examples pairs.
array<array<pair_t, 4>, 7> sets = {{
{{{0, 1}, {2, 3}, {4, 5}, {6, 7}}},
{{{0, 1}, {2, 3}, {4, 6}, {5, 7}}},
{{{0, 1}, {2, 3}, {4, 7}, {5, 6}}},
{{{0, 1}, {2, 3}, {5, 6}, {4, 7}}},
// snip
{{{2, 3}, {6, 7}, {4, 5}, {0, 1}}},
// snip
{{{6, 7}, {4, 5}, {1, 3}, {0, 2}}},
{{{6, 7}, {4, 5}, {2, 3}, {0, 1}}},
}};
for (unsigned i = 0; i < 7; ++i)
{
const array<pair_t, 4>& set = sets[i];
cout << rank(set) << ": ";
for (unsigned j = 0; j < 4; ++j)
cout << '{' << (unsigned)set[j][0] << ", " << (unsigned)set[j][1] << '}';
cout << endl;
}
return 0;
}
Output:
0: {0, 1}{2, 3}{4, 5}{6, 7}
1: {0, 1}{2, 3}{4, 6}{5, 7}
2: {0, 1}{2, 3}{4, 7}{5, 6}
3: {0, 1}{2, 3}{5, 6}{4, 7}
1259: {2, 3}{6, 7}{4, 5}{0, 1}
2518: {6, 7}{4, 5}{1, 3}{0, 2}
2519: {6, 7}{4, 5}{2, 3}{0, 1}

Insert vector {x, y, z} into another vector?

I'm looking for some pointers on inserting or pushing a vector into another vector.
The idea is I have vec1 = {1, 2, 3} for example.
Then I want to insert this into vec2 before next vec1 = {4, 5, 6} turns up.
The problem is I don't want vec 2 to read {1, 2, 3, 4, 5, 6}, I want it to read
vec2 = {1, 2, 3},
{4, 5, 6},... etc
Is this possible or I'm I completely mad. Any help will be great.
Thanks.
You can use a vector of vector of integers. Like this :
std::vector<std::vector<int>> vecofvecs = { {1,2,3}, {4,5,6} };
You can also use this :
#include <vector>
int main()
{
std::vector<std::vector<int>> vecofvecs;
std::vector<int> subvec1 = { 1,2,3 };
std::vector<int> subvec2 = { 4,5,6 };
vecofvecs.push_back(subvec1);
vecofvecs.push_back(subvec2);
return 0;
}

Generate all possible ordered subset from a set

I'm aware how to generate all possible subsets from a set incorporating bit twiddling. For instance,
//Get if nth position's bit is set
bool IsBitSet(int num, int bit)
{
return 1 == ((num >> bit) & 1);
}
int subsetMaxIterCount = pow(2, someList.size());
for (int i = 0; i < subsetMaxIterCount; i++) {
vector<A> subset;
for (size_t i = 0; i < jobList.size(); i++)
{
if (IsBitSet(jobSubsetIdx, i)) {
//Add to subset here
}
}
//Here we have a subset for some i
}
However, this doesn't take into account of ordering.
For instance, if I had a set of {1, 2, 3}, the above algorithm generates subsets of:
{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1,2,3}
What I need in reality is this
{}, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1,2,3}, {2, 1}, {2, 1, 3}, {2, 3, 1}, {3, 1}, {3, 2}, {3, 1, 2}, {3, 2, 1}
Not sure if the above list is exhaustive. What's an effective algorithm in generating something like this? (Is this all possible subsets with permutation by the way?)
The way we generate the subsets using bit twiddling, every subset is sorted within it e.g. {1, 2, 3}, {2, 3}, {1, 3}. You can generate permutation for each subset using next_permutation
vector<vector<int>> mySubsetGenerator(vector<vector<int>>& subsets) {
vector<vector<int>> extendedSubset;
for(int i = 0; i < subsets.size(); ++i) {
do {
extendedSubset.push_back(subsets[i]);
} while(next_permutation(subsets[i].begin(), subsets[i].end()));
}
return extendedSubset;
}
Moreover, you can use only backtracking to generate all possible permutations by taking one or more elements of array.

Initializing multiple data structures inside of each other c++11

I was looking for help on how to initialize the following data structure inside of my constructor for backtracking:
stack<tuple<vector<set<int> >, int, int> > record; //none of the structures have been initialized yet
Thank you all for your help.
When you have a complex type like that, it is helpful to divide the type into fundamental types before figuring out how to initialize it.
Divide your type into fundamental types, it looks like:
stack<tuple<vector<set<int> >, int, int> > record;
^ ^
| |
tuple<vector<set<int> >, int, int>
^ ^ ^ ^ ^ ^
| | | | | |
vector<set<int> >
^ ^
| |
set<int>
^ ^
| |
To initialize an object of such a type, you'll have to figure out how to build up from the constituent fundamental types.
Initialize an int.
int a{0};
Initialize a set<int>.
set<int> b{1, 2};
Initialize a vector<set<int>>.
vector<set<int>> c{ {1, 2}, {2, 3, 4}, {4, 5, 6, 8} };
Initialize a tuple<vector<set<int>>, int, int>.
tuple<vector<set<int>>, int, int> d{ { {1, 2}, {2, 3, 4}, {4, 5, 6, 8} }, 10, 20};
However, you cannot use the same strategy to initialize stack since std::stack does not have a constructor that you can use like:
stack<int> e{1, 3, 5};
That means, you can't initialize a stack<tuple<vector<set<int>>, int, int>> as:
stack<tuple<vector<set<int> >, int, int> > record
{
{{ {1, 2}, {2, 3, 4}, {4, 5, 6, 8} }, 10, 20},
{{ {1, 2}, {2, 3, 4}, {4, 5, 6, 8} }, 10, 20}
};
Your only choice is to default construct record and add items to it.
stack<tuple<vector<set<int> >, int, int> > record;
using item_type = decltype(record)::value_type;
record.push(item_type{{ {1, 2}, {2, 3, 4}, {4, 5, 6, 8} }, 10, 20});
record.push(item_type{{ {1, 2}, {2, 3, 4}, {4, 5, 6, 8} }, 10, 20});

subarray of 2D array to NULL

I have the following array in C++:
int arr[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
And I want to implement data like this:
arr[1] = NULL;
But this doesn't work. Thanks a lot for your help.

Categories