-1

I am looking for a way to find all combinations of a 30 numbers in numbersArray which has numbers between 0-1000.

        For example 1st combination is: 0,1,2,3,4,5,6......29,30
        For example 2nd combination is: 0,2,3,4,5,6,7......30,31
        For example 2rd combination is: 0,3,4,5,6,7,8......31,32

Then continue to find all combinations. Any number must only appear once in the series of 30 numbers.

The very important detail here is if it is possible while create those combinations, then use them straight away. With other words, not storing the combinations first and then iterating through them again. Which would mean double amount of iterations?

Thank you!

    void findcombinations()
    {
        //Declaring the array with 1000 indexes
        //The number of indexes can be up to 100,000 indexes
        int[] numbersArray = new int[1000];
        for (int i = 0; i < numbersArray.Length; i++)
        {
            numbersArray[i] = i; //Assign number from 0-1000
        }

        //How to find all combinations of 30 numbers between: 0-1000?
        //For example 1st combination is: 0,1,2,3,5,6,7......29,30
        //For example 2nd combination is: 0,2,3,5,6,7,8......30,31
        //For example 2rd combination is: 0,3,5,6,7,8,9......31,32

        //How to dynamically find all combinations of a group of 30 numbers between 0-1000?
        
        //Not perheps exactly use the below approach because that would mean that we already have filled the
        //Array with the combinations.

        //I am trying to see if there is a dynamic approach where the combinations are produced right away so 
        //They can be used straight away as they are produced?
        int[,] allCombinations = new int[???,30]; ///??? How many combinations of 30 numbers 
        for (int i = 0; i < allCombinations.Length; i++)
        {
            for (int i2 = 0; i2 < allCombinations.GetLength(i); i2++)
            {
                //Do something with the combination of numbers here
            }
        }
    }
Andreas
  • 1,121
  • 4
  • 17
  • 34
  • I have no clue what this means `all combinations of a group of 30 numbers` ?!? What is the combination you are talking about is this sequence of numbers `5,15,27,1,4,97,772,147,173...` - 30 random numbers - a combination? or are you just simply trying to split your 1000 into blocks of 30 numbers like this `numbersArray.GroupBy(x => x % 30)` see here: https://dotnetfiddle.net/DBaOOu – Rand Random Jul 20 '20 at 15:39
  • I am trying to find all possible combinations that could exist with 30 numbers between 0-1000. I am not grouping anything in chunks or anything like this or doing anything random. I am just looking to find all combinations. For example `0-29` is 30 numbers. Another combination of numbers are `1-30`. There can't be any duplicate numbers in the group. All numbers in the group of 30 numbers must be unique. There are a finite number of possible combinations which I try to find. `0-15 - 100-13` should also be one unique combination etc. – Andreas Jul 20 '20 at 15:44
  • Why do your 3 examples start with 0? Why is the 3rd example missing the 4? – Rand Random Jul 20 '20 at 15:47
  • @Rand Sorry, that was my mistake. 4 should not be missing. I corrected my post there now. I just start with 0 as an example. It can start however. It could be like this also: `5,6,8,15,35.... 40-60....65,66,68,80,504` That is also one combination of 30 unique numbers. So I am trying to find all possible combinations that exist. – Andreas Jul 20 '20 at 15:51
  • 1
    Did you know there are 2.43e57 diferent combinations of 30 elements of a set of 1000 elements? https://en.wikipedia.org/wiki/Combination – Jesús López Jul 20 '20 at 15:53
  • @Jesús oh is it so many combinations. Wow I never thought it was that many. I tried to understand the link but are there any formula to calculate: 2.43E57 ? I still look for a way to do it. I could use the same approach for less combinations. – Andreas Jul 20 '20 at 15:55
  • 1
    @Andreas: 1000! / (30! * (1000-30)!) – Jesús López Jul 20 '20 at 15:58
  • @JesúsLópez - I am bad at math, does that treat the combination `1,2,3` different than `3,2,1` or not? – Rand Random Jul 20 '20 at 15:59
  • @Rand @Jeus, interesting. That is true `1,2,3` and `3,2,1` would be the same combination as it contains the same numbers, so only 1 of them are needed. – Andreas Jul 20 '20 at 16:01
  • @RandRandom - from Jesus's link - "(unlike permutations) the order of selection does not matter" – Damien_The_Unbeliever Jul 20 '20 at 16:01
  • @Andreas they are the same combination because they have the same elements, no matter the order. – Jesús López Jul 20 '20 at 16:01
  • @Damien_The_Unbeliever - did you really expect from me to read the very first sentence of the link provided? my bad sorry :) – Rand Random Jul 20 '20 at 16:03
  • @Jesus Yes I see so there will actually then be 2.43e57 diferent combinations. It is many combinations. – Andreas Jul 20 '20 at 16:03
  • https://stackoverflow.com/questions/1952153/what-is-the-best-way-to-find-all-combinations-of-items-in-an-array – Mikael Jul 20 '20 at 16:04
  • @Jesus Yes I see so there will actually then be 2.43e57 diferent combinations. It is many combinations. I still would be interesting to see if there is any approach to find those combinations. I could use smaller samples. – Andreas Jul 20 '20 at 16:05
  • @Mikael I know I found that post before I posted but are not sure if I understand the solution. I can also see: `c.Add` which is very slow as I have benchmarked `.Add` with lists before. I think I try to see if there is as fast approach as possible without the `.Add` and `c.RemoveAt` – Andreas Jul 20 '20 at 16:11
  • @Mikael I think those are permutations (different ways to order a set). – Jesús López Jul 20 '20 at 16:12
  • @Andreas I wrote a subrutine in BASIC to calculate combinations when I was 20 years old, but now I 'm 58 and I think I would get a terrible headache if I try to write it today – Jesús López Jul 20 '20 at 16:15
  • @Jesús I understand, don't worry. I will try to continue to find a solution anyway. No worries :) – Andreas Jul 20 '20 at 16:16

2 Answers2

1

Here you have the solution:

using System;
using System.Collections.Generic;

namespace combinatory
{
    public class Combinations
    {
        private readonly int n;
        private readonly int k;
        private readonly int[] combination;

        public Combinations(int n, int k)
        {
            if (n <= 0) throw new ArgumentException("n argument must be greater than 0", nameof(n));
            if (k <= 0) throw new ArgumentException("k argument must be greater than 0", nameof(k));
            if (n < k) throw new ArgumentException("k argument must be greater or equals to n", nameof(k));

            this.n = n;
            this.k = k;

            combination = new int[k];

            for (int i = 0; i < k; i++)
            {
                combination[i] = i;
            }
        }

        public IEnumerable<int[]> Get()
        {
            yield return combination;
            while (TrySetNextCombination())
            {
                yield return combination;
            }
        }

        private bool TrySetNextCombination()
        {
            int incrementableIndex = findFirstIncrementableIndex();
            if (incrementableIndex < 0) return false;
            var value = combination[incrementableIndex];
            for (int i = incrementableIndex; i < k; i++)
            {
                combination[i] = ++value;
            }
            return true;
        }

        private int findFirstIncrementableIndex()
        {
            int index = k - 1;
            int threshold = n - 1;
            while (index >= 0)
            {
                if (combination[index] < threshold) return index;
                index--;
                threshold--;
            }
            return index;
        }
    }
}

The class Combinations has a constructor that takes n and k arguments. n is the number of elements in the set, k is the number of elements in the subset. It has the Get method, it enumerates all combinations. It is very memory efficient because it just need an array of k integers. The key point is to initialize the first combination and then calculate the next one.

This is how you can use it:

using System;

namespace combinatory
{
    class Program
    {
        static void Main(string[] args)
        {
            var combinations = new Combinations(6, 3);
            foreach (var comb in combinations.Get())
            {
                foreach (var v in comb)
                {
                    Console.Write(" ");
                    Console.Write(v);
                }
                Console.WriteLine();
            }
        }
    }
}

This is the output:

 0 1 2
 0 1 3
 0 1 4
 0 1 5
 0 2 3
 0 2 4
 0 2 5
 0 3 4
 0 3 5
 0 4 5
 1 2 3
 1 2 4
 1 2 5
 1 3 4
 1 3 5
 1 4 5
 2 3 4
 2 3 5
 2 4 5
 3 4 5
Jesús López
  • 8,338
  • 7
  • 40
  • 66
  • Thank you very much. This really worked out great. I did test it now and it seems to produce the outputs right. I will try more with the code. It was alot of code you wrote and so fast also. I hope you are okay then :) I will experiment with this code. It was great! Thank you! – Andreas Jul 20 '20 at 17:27
1

In fact, if you want just the number of combinations, there's a mathematical compution for this:

n! / (p! . (n - p)!)

Where n is the total number count (1000), and p is de picked count (30).

Source: https://en.m.wikipedia.org/wiki/Combination

Pieterjan
  • 2,738
  • 4
  • 28
  • 55