1

I have a 2D array for a lottery I am creating. Basically it's a set of 2 integers: int[,] coupon = new int[rowAmount, numAmount]; Where rowAmount is the amount of rows, and numAmount is the amount of numbers in that row.

Now I need to select the numbers for each row, however there may not be duplicates of a number within a specific row.

        for (int r = 0; r < rowAmount; ++r)
    {
        for (int n = 0; n < numAmount; ++n)
        {
            userNum = lotRng.Next(1, numAmount * rngMult);
            while (COUPON CONTAINS DUPLICATE NUMBER ON SECOND SPOT )
            {
                userNum = lotRng.Next(1, numAmount * rngMult);
            }
            coupon[r, n] = userNum;
        }                    
    }

My issue is the while part, I cannot figure out how to check if coupon contains the userNum on the second slot(The numAmount slot). For lists and stuff I used to just do list.Contains() but that doesn't seem to work on here.

Gustavo A.
  • 25
  • 7

5 Answers5

0

Depending on the size of your array is wether it makes sense to optimize performance.

Depending on that one possibility would be to sort the array and use Array.BinarySearch .

You have to sort your array for that.

https://msdn.microsoft.com/en-us/library/2cy9f6wb(v=vs.110).aspx

So you have a number of possibilities to optimize data structure.

Philm
  • 3,448
  • 1
  • 29
  • 28
0

Solution with loops in an array. Not elegant, but you could refactor the search loops in an own method to look better. But as a second point, in this case a linear search like shown is not a really fast solution either.

Only inner part of the 2 for-loops, not full code (as in other answers by me here):

bool foundDup;
do
{
    userNum = lotRng.Next(1, numAmount * rngMult);
    foundDup = false;
    for (var x = 0; x < coupon.GetLength(1); x++) //Iterate over second dimension only
        if (coupon[r, x] == userNum)
        {   foundDup = true;
            break;
        }
} while (foundDup);
coupon[r, n] = userNum;

In the special context of this question, you can optimize the loop:

for (var x = 0; x < n; x++)
Philm
  • 3,448
  • 1
  • 29
  • 28
0

Solution with 2D jagged arrays: If you want to access rows and columns in C#, a jagged array is very convenient and unless you care very much how effient the array ist stored internally, jagged array are to recommend strongly for that.

Jagged arrays are simply arrays of arrays.

const int rowAmount = 1000;
const int numAmount=1000;
const int rngMult = 10;
int userNum;
Random lotRng = new Random();
var coupon = new int[rowAmount][];
for (int r = 0; r < rowAmount; r++)
{
    coupon[r] = new int[numAmount];
    for (int n = 0; n < numAmount; ++n)
    {
        do userNum = lotRng.Next(1, numAmount * rngMult);
        while (Array.Exists(coupon[r], x => x == userNum));

        coupon[r, n] = userNum;
    }
}

The above function Array.Exists works only for 1 dimension what is enough here, and needs no Linq. The same as above with Linq method .Any :

        while (coupon[r].Any(x => x == userNum));

If you would have to search in two dimensions for a double value, you would need a loop more again, but still on nested loop level less than without this.

Linq is elegant, but normally not the fastest method (but you would have to handle with very big arrays of multi-million sizes for that to matter).

For other possibilities of using Linq, look for example here: How to use LINQ with a 2 dimensional array

Another idea would be to make one-dimensional array of size rowAmount*numAmount. It needs a little bit of thinking, but allows most simple and fastest access of searching.

Community
  • 1
  • 1
Philm
  • 3,448
  • 1
  • 29
  • 28
0

Solution with an array of lists is one of my favourites for this. It's very similar to my other with jagged arrays but faster- because List search is most efficient and Linq searches are not.

const int rowAmount = 1000;
const int numAmount=1000;
const int rngMult = 10;
Random lotRng = new Random();
var coupon = new List<int>[rowAmount];
int userNum;

for (int r = 0; r < rowAmount; r++)
{
    coupon[r]= new List<int>();
    for (int n = 0; n < numAmount; ++n)
    {
        do userNum = lotRng.Next(1, numAmount * rngMult);
        while (coupon[r].Contains(userNum));
        coupon[r].Add(userNum);
    }
}

Of course it would be also possible to use a list of lists (kind of 2D lists), if necessary.

var couponLoL = new List<List<int>>();

The following quick and dirty way show a possible way of copying a 2D array to a list, but not to recommend here for several reasons (loop, boxing for value types):

var coupon= new int[rowAmount,numAmount];

[..]

        do userNum = lotRng.Next(1, numAmount * rngMult);
        while (coupon.Cast<int>().ToList().Contains(userNum));

In this special case it makes even less sense, because this would look in the whole 2D array for the double value. But it is worth knowing how to convert from 2D to 1D array (and then in a list).

Philm
  • 3,448
  • 1
  • 29
  • 28
-1

As you say in your comment you need to check all n fields vs. your new userNum. You can solve this with the following code:

for (int r = 0; r < rowAmount; ++r)
{
  for (int n = 0; n < numAmount; ++n)
  {
    userNum = lotRng.Next(1, numAmount * rngMult);
    
    for (int x = 0; x < coupon.GetLength(1); x++) //Iterate over your second dimension again
    {
      while (coupon[r,x] == userNum)
      {
        userNum = lotRng.Next(1, numAmount * rngMult);
      }
    }
    coupon[r, n] = userNum;
  }
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Sebi
  • 3,879
  • 2
  • 35
  • 62
  • Sorry. But to me this code looks as if it is NOT working and there is a serious flaw: The inner loops are wrong side out. For example: The new found no for x= 100 may be a double of x=99 so testing for index 99 before was worthless. – Philm May 06 '17 at 12:33