Given an arbitrary set of numbers S = {1..n} and size k, I need to print all possible combinations of size k ordered by the sum of the combinations.
Let's say S = {1, 2, 3, 4, 5} and k = 3, a sample output would be:
1 2 3 = 6
1 2 4 = 7
1 2 5 = 8
1 3 4 = 8
1 3 5 = 9
2 3 4 = 9
2 3 5 = 10
1 4 5 = 10
2 4 5 = 11
3 4 5 = 12
The first idea that came to my mind is to sort S (if not already sorted) and then perform a BFS search, having a queue of combinations sorted by sum. This is because I want to generate the next combination only if requested (iterator like). But this seems like an overkill and I think that there should be an easier solution. How can this be solved?
Edit:
This is my original idea:
1. Sort S
2. Pick the first k numbers and add them to the queue as a single node (because this is the combination with the smallest sum)
3. While the queue is not empty - pop the first node, output it, and generate successors.
Generating successors:
1. Start with the first number in the node. Make a copy of a node. Find the smallest unselected value that is > than the number, and assign this value.
2. Verify that this node hasn't been seen and calculate the sum.
3. Add the node to the queue.
4. Repeat 1-3 for all of the remaining numbers in the node.
Example:
Queue q = { {1, 2, 3} = 6 }
Pop front, output
1 2 3 = 6
Generate {4, 2, 3} = 9, {1, 4, 3} = 8, {1, 2, 4} = 7
Seen { {1, 2, 3}, {4, 2, 3}, {1, 4, 3}, {1, 2, 4} }
Queue q = { {1, 2, 4} = 7, {1, 4, 3} = 8, {4, 2, 3} = 9 }
Pop front, output
1 2 3 = 6
1 2 4 = 7
Generate {3, 2, 4} = 9 (seen - discard), {1, 3, 4} = 8 (seen - discard), {1, 2, 5} = 8 }
Seen { {1, 2, 3}, {4, 2, 3}, {1, 4, 3}, {1, 2, 4}, {1, 2, 5} }
Queue q = { {1, 2, 5} = 8, {1, 4, 3} = 8, {4, 2, 3} = 9 }
Pop front, output
1 2 3 = 6
1 2 4 = 7
1 2 5 = 8
Generate {3, 2, 5} = 10, {1, 3, 5} = 9
Seen { {1, 2, 3}, {4, 2, 3}, {1, 4, 3}, {1, 2, 4}, {1, 2, 5}, {3, 2, 5}, {1, 3, 5} }
Queue q = { {1, 4, 3} = 8, {1, 5, 3} = 9, {1, 3, 5} = 9, {3, 2, 5} = 10, {1, 4, 5} = 10, {4, 2, 5} = 11 }
...
...
javascript sample like below;
<!DOCTYPE html>
<html>
<head>
<meta charset = utf-8>
<title>s{1..n} by k</title>
</head>
<body>
<header>s{1..n} by k</header>
<form action="#" onsubmit="return false;">
s:<input type="text" id="sArrayObj" name="sArrayObj" value="4 5 1 8 9 3 6 7"/><br/>
n:<input type="text" id="kVarObj" name="kVarObj" value="3"/><br/>
<button id="scan" name="scan" onclick="scanX()"> CALCULATE </button><br/>
<textarea id="scanned" name="scanned" cols=40 rows=20>
</textarea>
</form>
<script>
const headFactorial = n => {
if ( n > 1 ) return n * headFactorial( n - 1 );
else return 1;
}
const tailFactorial = n => {
if ( n === 1 ) return 1;
else return n * tailFactorial( n - 1 );
}
const combinations = ( collection, combinationLength ) => {
let head, tail, result = [];
if ( combinationLength > collection.length || combinationLength < 1 ) { return []; }
if ( combinationLength === collection.length ) { return [ collection ]; }
if ( combinationLength === 1 ) { return collection.map( element => [ element ] ); }
for ( let i = 0; i < collection.length - combinationLength + 1; i++ ) {
head = collection.slice( i, i + 1 );
tail = combinations( collection.slice( i + 1 ), combinationLength - 1 );
for ( let j = 0; j < tail.length; j++ ) { result.push( head.concat( tail[ j ] ) ); }
}
return result;
}
const sumArr = (anArr) => {
var s=0;
for (j=0; j < anArr.length; j++) s += 1*anArr[j];
return s;
}
function scanX(){
sArray = document.getElementById("sArrayObj").value.split(" ");
kVar = document.getElementById("kVarObj").value;
sArray.sort();
resultObj= document.getElementById("scanned");
resultObj.value = "";
//for (i=0;kVar > i;i++){
// resultObj.value+=sArray[i]+' ';
//}
resultArr = combinations(sArray, kVar);
for (i=0;i<resultArr.length;i++){
resultObj.value += resultArr[i]+"="+sumArr(resultArr[i])+"\n";
}
return false;
}
</script>
</body>
</html>
Related
So the aim is to take two arrays as shown below
int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int k[4] = {1, 2, 3, 4};
and add each element of k to each element of x in a loop as shown
1 2 3 4 5 6 7 8 9 10
+1 +2 +3 +4 +1 +2 +3 +4 +1 +2
This should give us a final array [2, 4, 6, 8, 6, 8, 10, 12, 10, 12].
Any suggestions as to how I could achieve this in C++
Loop through the indexes of the larger array, using the modulus (%) operator to wrap-around the indexes when accessing the smaller array.
int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int k[4] = {1, 2, 3, 4};
int res[10];
for (int i = 0; i < 10; ++i) {
res[i] = x[i] + k[i % 4];
}
Online Demo
With % you can have the wrap-around behavior and with std::size(from C++17 onwards) the size of the array.
#include <algorithm>
#include <iostream>
int main()
{
int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int k[4] = {1, 2, 3, 4};
for(int i = 0; i < std::size(x); ++i)
{
x[i] = x[i] + k[i%std::size(k)];
}
//lets confirm if x has the right elmennts
for(const int& element: x)
{
std::cout<< element<<std::endl;
}
}
Note that here i have not used a separate array to store the resulting array. Instead the elements are added into the original array x. Storing the result in a new array is trivial.
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}
I have an array of arrays of things
typedef std::vector<thing> group;
std::vector<group> groups;
things could be compared like so
int comparison(thing a, thing b);
where the return value is 0, 1 or 2
0 means that the things are not alike
1 means that they are alike and a is more specific or equal to b
2 means that they are alike and b is more specific or equal to a
and I am looking for a function that would return me a group that contains all things that appear in every group.
std::getgroup(groups.begin(), groups.end(), myComparisonFunction);
the problem is I have no idea what this function may be called, if it does even exist, or what the closest thing to it would be.
Eventually, what you want is an intersection. Luckily, there is std::set_intersection which almost does what you need. Here's a simple example on std::vector<std::vector<int>>. You can easily change it to work with your thing:
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int> getGroup(const std::vector<std::vector<int>>& groups) {
std::vector<int> group;
std::vector<int> temp = groups[0];
std::sort(temp.begin(), temp.end());
for ( unsigned i = 1; i < groups.size(); ++i ) {
group = std::vector<int>();
std::vector<int> temp2 = groups[i];
std::sort(temp2.begin(), temp2.end());
std::set_intersection(temp2.begin(), temp2.end(),
temp.begin(), temp.end(),
std::back_inserter(group));
temp = group;
}
return group;
}
int main() {
std::vector<std::vector<int>> groups = { {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{1, 2, 3, 5, 6, 7, 8, 10},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
{1, 3, 4, 5, 6, 9, 10},
{1, 2, 6, 7, 8, 9, 10},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} };
for ( auto g : getGroup(groups) )
std::cout << g << "\n";
return 0;
}
This will print:
1
6
10
Let's suppose we have two childs who want to get same number or coins (coin nominals 1,2,6,12). Childs don't care about the value.
Example container of permutations which I want to share between two childs:
{1, 1, 1, 1, 1, 1},
{1, 1, 2, 2},
{1, 2, 1, 2},
{1, 2, 2, 1},
{2, 1, 1, 2},
{2, 1, 2, 1},
{2, 2, 1, 1}
Now I`d like to have collections without duplicates:
child A child B
2 2 1 1
2 1 2 1
1 1 2 2
1 1 1 1 1 1
That permutations are wrong:
1 2 1 2
1 2 2 1
2 1 1 2
because
child A child B
1 2 1 2
is permutation of
child A child B
2 1 2 1
which we already have. These collections: 1 2 2 1 and 2 1 1 2 are permutations, as well.
My solution is here, works correctly for that particular input but if you add more coins with different nominals, it doesn't!
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int main()
{
vector<vector<int>> permutations =
{
{1, 1, 1, 1, 1, 1},
{1, 1, 2, 2},
{1, 2, 1, 2},
{1, 2, 2, 1},
{2, 1, 1, 2},
{2, 1, 2, 1},
{2, 2, 1, 1}
};
vector<pair<unordered_multiset<int>, unordered_multiset<int>>> childSubsets;
for(const auto ¤tPermutation : permutations)
{
size_t currentPermutationSize = currentPermutation.size();
size_t currentPermutationHalfSize = currentPermutationSize / 2;
//left
unordered_multiset<int> leftSet;
for(int i=0;i<currentPermutationHalfSize;++i)
leftSet.insert(currentPermutation[i]);
bool leftSubsetExist = false;
for(const auto &subset : childSubsets)
{
if(subset.first == leftSet)
{
leftSubsetExist = true;
break;
}
}
//right
unordered_multiset<int> rightSet;
for(int i = currentPermutationHalfSize; i < currentPermutationSize; ++i)
rightSet.insert(currentPermutation[i]);
bool rightSubsetExist = false;
for(const auto &subset : childSubsets)
{
if(subset.second == rightSet)
{
rightSubsetExist = true;
break;
}
}
//summarize
if(!leftSubsetExist || !rightSubsetExist) childSubsets.push_back({leftSet, rightSet});
}
cout << childSubsets.size() << endl;
}
How to change the solution to make optimal and less complex?
You should add
if (leftSubsetExist)
continue;
after first cycle (as optimization)
Could you add some "wrong" permutations (with another coins)?
Here is my array:
int grid[gridsize+1] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2, 4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6, 4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8, 4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8 };
Each number represents a colour, I would like to create multiple arrays for each unique number. The created arrays will store the locations of that number from the original array.
e.g
colour1[5]
[0]=0 //because the number 1 is stored in element 0.
[1]=1
[2]=8
[3]=9
The numbers in grid will change every time I run, so things need to be dynamic?
I can write inefficient code that accomplishes this, but it's just repetitive and I can't comprehend a way to turn this into something I can put in a function.
Here is what I have;
int target_number = 1
grid_size = 64;
int counter = -1;
int counter_2 = -1;
int colour_1;
while (counter < grid_size + 1){
counter = counter + 1;
if (grid[counter] == target)
counter_2 = counter_2 + 1;
colour_1[counter_2] = counter;
}
}
I have to do this for each colour, when I try to make a function, it cannot access the main array in main so is useless.
You can just use vector<vector<int>> to represent your counters. No maps or sorting are needed.
EDIT: added additional pass to determine maximum color, so no run-time resize is needed.
Here is the code:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
int grid[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, /*...*/};
const size_t gridSize = std::end(grid) - std::begin(grid);
int maxColor = *std::max_element(std::begin(grid), std::end(grid));
std::vector<std::vector<int>> colorPos(maxColor);
for (size_t i = 0; i < gridSize; ++i)
colorPos[grid[i] - 1].push_back(i);
for (size_t i = 0; i < colorPos.size(); ++i) {
std::cout << (i + 1) << ": ";
for (int p : colorPos[i])
std::cout << p << ' ';
std::cout << std::endl;
}
return 0;
}
The output:
1: 0 1 8 9 10 17
2: 2 3 4 5 6 7 14 15 22 30
3: 11 12 13 19 20 28
4: 16 24 32 33 40 48 56
5: 18 25 26 27 34 35 36 44
6: 21 23 29 31 37 38 39
7: 41 42 49 50 57 58 59 60
8: 43 45 46 47 51 52 53 54 55 61 62 63
I think you'd be best off using a counting sort, which is a sorting algorithm that works very well for sorting large groups of simple types with many duplicate values in better than O(n log n) time. Here's some sample code, annotated for clarity:
// set up our grid
int grid_raw[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2, 4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6, 4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8, 4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8};
// build a vector using our raw list of numbers. This calls the range constructor:
// (number 3) http://www.cplusplus.com/reference/vector/vector/vector/
// The trick to using sizeof is that I don't have to change anything if my grid's
// size changes (sizeof grid_raw gives the number of bytes in the whole array, and
// sizeof *grid_raw gives the number of bytes in one element, so dividing yields
// the number of elements.
std::vector<int> grid(grid_raw, grid_raw + sizeof grid_raw / sizeof *grid_raw);
// count the number of each color. std::map is an associative, key --> value
// container that's good for doing this even if you don't know how many colors
// you have, or what the possible values are. Think of the values in grid as being
// colors, not numbers, i.e. ++buckets[RED], ++buckets[GREEN], etc...
// if no bucket exists for a particular color yet, then it starts at zero (i.e,
// the first access of buckets[MAUVE] will be 0, but it remembers each increment)
std::map<int, int> buckets;
for (vector<int>::iterator i = grid.begin(); i != grid.end(); ++i)
++buckets[*i];
// build a new sorted vector from buckets, which now contains a count of the number
// of occurrences of each color. The list will be built in the order of elements
// in buckets, which will default to the numerical order of the colors (but can
// be customized if desired).
vector<int> sorted;
for (map<int, int>::iterator b = buckets.begin(); b != buckets.end(); ++b)
sorted.insert(sorted.end(), b->second, b->first);
// at this point, sorted = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, ...}
Read more about the Counting Sort (includes example python code)
Here's an ideone that demonstrates sorting your grid.
I'm not 100% sure this answers your question... but you included sorting in the title, even though you didn't say anything about it in the body of your question.
Maybe it would be better to use some associative container as for example std::unordered_map or std::multimap.
Here is a demonstrative program
#include <iostream>
#include <map>
int main()
{
int grid[] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2,
4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6,
4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8,
4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8
};
std::multimap<int, int> m;
int i = 0;
for ( int x : grid )
{
m.insert( { x, i++ } );
}
std::multimap<int, int>::size_type n = m.count( 1 );
std::cout << "There are " << n << " elements of color 1:";
auto p = m.equal_range( 1 );
for ( ; p.first != p.second ; ++p.first )
{
std::cout << ' ' << p.first->second;
}
std::cout << std::endl;
return 0;
}
The output
There are 6 elements of color 1: 0 1 8 9 10 17
Or
#include <iostream>
#include <map>
int main()
{
int grid[] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 3, 3, 3, 2, 2,
4, 1, 5, 3, 3, 6, 2, 6, 4, 5, 5, 5, 3, 6, 2, 6,
4, 4, 5, 5, 5, 6, 6, 6, 4, 7, 7, 8, 5, 8, 8, 8,
4, 7, 7, 8, 8, 8, 8, 8, 4, 7, 7, 7, 7, 8, 8, 8
};
std::multimap<int, int> m;
int i = 0;
for ( int x : grid )
{
m.insert( { x, i++ } );
}
for ( auto first = m.begin(); first != m.end(); )
{
auto n = m.count( first->first );
std::cout << "There are " << n
<< " elements of color " << first->first << ":";
auto p = m.equal_range( first->first );
for ( ; p.first != p.second ; ++p.first )
{
std::cout << ' ' << p.first->second;
}
std::cout << std::endl;
first = p.first;
}
return 0;
}
the output is
There are 6 elements of color 1: 0 1 8 9 10 17
There are 10 elements of color 2: 2 3 4 5 6 7 14 15 22 30
There are 6 elements of color 3: 11 12 13 19 20 28
There are 7 elements of color 4: 16 24 32 33 40 48 56
There are 8 elements of color 5: 18 25 26 27 34 35 36 44
There are 7 elements of color 6: 21 23 29 31 37 38 39
There are 8 elements of color 7: 41 42 49 50 57 58 59 60
There are 12 elements of color 8: 43 45 46 47 51 52 53 54 55 61 62 63
If you are not forced to use plain arrays, I can propose a map of colors to a vector of positions:
the map is an associative container, that for any color key returns a reference
the referenced used here will be a vector (a kind of dynamic array) containing all the positions.
Your input grid contains color codes:
typedef int colorcode; // For readability, to make diff between counts, offsets, and colorcodes
colorcode grid[] = { 1, 1, /* .....input data as above.... */ ,8 };
const size_t gridsize = sizeof(grid) / sizeof(int);
You would then define the color map:
map<colorcode, vector<int>> colormap;
// ^^^ key ^^^ value maintained for the key
With this approach, your color1[..] would then be replaced by a more dynamic corlormap[1][..]. And it's very easy to fill:
for (int i = 0; i < gridsize; i++)
colormap[grid[i]].push_back(i); // add the new position to the vector returned for the colormap of the color
To verify the result, you may iterate through the map, and for each existing value iterate through the positions:
for (auto x : colormap) { // for each color in the map
cout << "Color" << x.first << " : "; // display the color (key)
for (auto y : x.second) // and iterate through the vector of position
cout << y << " ";
cout << endl;
}
You don't know for sure how many different color codes you have, but you want to store for accodes