Dave Gordon
Dave Gordon

Reputation: 1835

C# iterate a continuously growing multi dimensional array

Imagine I wanted to iterate from A to Z. We would use either Foreach or For loop. After attaining Z I would then like to iterate from AA to ZZ, so it starts at AA, then goes to AB, AC...AZ, BA, BC..BZ..ZA,ZB, ZZ. At which point we would move to three chars, then 4 etc up to an undefined point.

Because we don't have a defined length for the array we cannot use nested for loops... so

Question: How can this be done?

Note, No code has been given because we all know how to foreach over an array and nest foreach loops.

Upvotes: 2

Views: 313

Answers (6)

Sachin Sathe
Sachin Sathe

Reputation: 29

Try the following. This is a method to generate the appropriate string for a given number. You can write a for loop for however many number of iterations you want.

string SingleEntry(int number)
{
    char[] array = " ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToArray();
    Stack<string> entry = new Stack<string>();
    List<string> list = new List<string>();
    int bas = 26;

    int remainder = number, index = 0;
    do
    {
        if ((remainder % bas) == 0)
        {
            index = bas;
            remainder--;
        }
        else
            index = remainder % bas;

        entry.Push(array[index].ToString());
        remainder = remainder / bas;
    }
    while (remainder != 0);

    string s = "";
    while (entry.Count > 0)
    {
        s += entry.Pop();
    }
    return s;
}

Upvotes: 1

Maksim Simkin
Maksim Simkin

Reputation: 9679

You could do something like this, it gives me unending output of your pattern (sorry, not exact your pattern, but you understand how to do it)

public static  IEnumerable<string> Produce()
{
   string seed = "A";
   int i = 0;
   while (true)
   {
       yield return String.Join("", Enumerable.Repeat(seed, i));                
       if (seed == "Z")
       {
          seed = "A";
          i++;
       }
       else
       {
          seed = ((char)(seed[0]+1)).ToString();
       }
    }
}

And than :

foreach (var s in Produce())
{
   //Do something
}

EDIT I have desired output with this method :

public static  IEnumerable<string> Produce()
{
    int i = 1;
    while (true)
    {
        foreach(var c in produceAmount(i))
        {
            yield return c;
        }
        i++;
    }
}

private static IEnumerable<string> produceAmount(int i)
{
    var firstRow = Enumerable.Range('A', 'Z' - 'A'+1).Select(x => ((char)x).ToString());
    if (i >= 1)
    {
        var second = produceAmount(i - 1);
        foreach (var c in firstRow)
        {
            foreach (var s in second)
            {
                yield return c + s;
            }
        }
    }
    else
    {
        yield return "";
    }
 }

Upvotes: 2

bottaio
bottaio

Reputation: 5073

The way to go is to use simple recursive approach. C# is a good language to present an idea with the use of generators:

private static IEnumerable<string> EnumerateLetters(int length) {
    for (int i = 1; i <= length; i++) {
        foreach (var letters in EnumerateLettersExact(i)) {                  
            yield return letters;
        }
    }
}

private static IEnumerable<string> EnumerateLettersExact(int length) {
    if (length == 0) {
        yield return "";
    }
    else {
        for (char c = 'A'; c <= 'Z'; ++c) {
            foreach (var letters in EnumerateLettersExact(length - 1)) {
                yield return c + letters;
            }
        }    
    }
}

private static void Main(string[] args) {
    foreach (var letters in EnumerateLetters(2)) {
        Console.Write($"{letters} ");
    }
}

EnumerateLetters generates successive sequences of letters. The parameter decides up to which length would you like to request sequences.

EnumerateLettersExact takes care of generating sequences recursively. It can either be empty or is a concatenation of some letter with all sequences of shorter length.

Upvotes: 1

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

Yet another generator (adding 1 to a number with radix == 26: A stands for 0, B for 1, ... Z for 25):

// please, notice, that Generator() can potentially spawn ifinitely many items 
private static IEnumerable<String> Generator() {
  char[] data = new char[] { 'A' }; // number to start with - "A"

  while (true) {
    yield return new string(data);

    // trying to add one
    for (int i = data.Length - 1; i >= 0; --i)
      if (data[i] == 'Z') 
        data[i] = 'A';
      else {
        data[i] = (char) (data[i] + 1); 

        break;
      }

    // have we exhausted N-length numbers?  
    if (data.All(item => item == 'A'))
      data = Enumerable
        .Repeat('A', data.Length + 1) // ... continue with N + 1-length numbers  
        .ToArray();
  }
}

Test

   // take first 1000 items:
   foreach (var item in Generator().Take(1000)) 
     Console.WriteLine(item); 

Outcome

  A
  B
  C 
  ..
  X
  Y
  Z
  AA
  AB
  ..
  AZ
  BA
  BB
  BC
  ..
  ZY
  ZZ
  AAA
  AAB
  AAC
  ..
  ALK
  ALL

Upvotes: 2

Chris
Chris

Reputation: 27599

Here's some code that will do what you want. Full explanation follows but in summary it takes advantage of the fact that once you have done all the letters of a given length you do A followed by that entire sequence again then B followed by the entire sequence again, etc.

private IEnumerable<string> EnumerateLetters()
{
    int count = 1;
    while (true)
    {
        foreach(var letters in EnumerateLetters(count))
        {
            yield return letters;
        }
        count++;
    }
}

private IEnumerable<string> EnumerateLetters(int count)
{
    if (count==0)
    {
        yield return String.Empty;
    }
    else
    {
        char letter = 'A';  
        while(letter<='Z')
        {
            foreach(var letters in EnumerateLetters(count-1))
            {
                yield return letter+letters;
            }
            letter++;
        }
    }
}

There are two methods. The first is the one that you call and will generate an infinite sequence of letters. The second does the recursion magic.

The first is pretty simple. it has a count of how many letters we are on, calls the second method with that count and then enumerates through them returning them. Once it has done all for one size it increases the count and loops.

The second method is the one that does the magic. It takes in a count for the number of letters in the generated string. If the count is zero it returns an empty string and breaks.

If the count is more than one it will loop through the letters A to Z and for each letter it will append the sequence that it one shorter than it to the A. Then for the B and so on.

This will then keep going indefinitely.

The sequence will keep generating indefinitely. Because it uses recursion it would be theoretically possible to start stack overflowing if your letter string becomes too long but at one level of recursion per letter in the string you will need to be getting up to very long strings before you need to worry about that (and I suspect if you've gone that far in a loop that you'll run into other problems first).

The other key point (if you are not aware) is that yield return uses deferred execution so it will generate each new element in the sequence as it is needed so it will only generate as many items as you ask for. If you iterate through five times it will only generate A-E and won't have wasted any time thinking about what comes next.

Upvotes: 2

Mark Slingerland
Mark Slingerland

Reputation: 21

Your're about to have an array from A to Z [A,...,Z]. Then your going to make multiple for loops

for example:

PSEUDOCODE
foreach(in array){
    first = declare first variable (array)
    foreach(in array{
           second =declare 2nd variable (array)
           return first + second
    }
}

Upvotes: 1

Related Questions