C#迭代不断增长的多维数组

问题描述 投票:2回答:6

想象一下,我想从A迭代到Z.我们将使用ForeachFor循环。达到Z后,我想从AA到ZZ迭代,所以从AA开始,然后到AB,AC ... AZ,BA,BC..BZ..ZA,ZB,ZZ。在这一点上,我们将移动到三个chars,然后是4等等到一个未定义的点。

因为我们没有为数组定义长度,所以我们不能使用嵌套的for循环......所以

问题:如何做到这一点?

注意,没有给出代码,因为我们都知道如何在数组上嵌套foreach并嵌套foreach循环。

c# arrays
6个回答
1
投票

要走的路是使用简单的递归方法。 C#是一种使用生成器来表达想法的好语言:

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生成连续的字母序列。参数决定了您要求序列的长度。

EnumerateLettersExact负责递归生成序列。它可以是空的,也可以是具有较短长度的所有序列的某个字母的串联。


1
投票

这里有一些代码可以满足您的需求。完整的解释如下,但总的来说,它利用了这样的事实:一旦你完成了给定长度的所有字母,你再做一个A,然后是整个序列,然后是B,然后是整个序列,等等。

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++;
        }
    }
}

有两种方法。第一个是你调用的那个,它将生成一个无限的字母序列。第二个是递归魔法。

第一个很简单。它有一个我们在多少个字母的数量,用该计数调用第二个方法,然后枚举通过它们返回它们。一旦完成一个大小的全部操作,它就会增加计数和循环。

第二种方法就是魔术。它会计算生成的字符串中的字母数。如果计数为零,则返回空字符串并中断。

如果计数大于1,它将循环通过字母A到Z,并且对于每个字母,它将比它更短的序列附加到A.然后对于B,依此类推。

然后这将无限期地继续下去。

序列将无限期地产生。因为它使用递归,理论上如果你的字母字符串变得太长就会开始堆栈溢出,但是在字符串中每个字母的一个递归级别,你需要在你需要担心之前得到很长的字符串(而且我怀疑如果你已经走了一圈,你会先遇到其他问题)。

另一个关键点(如果您不知道)是yield return使用延迟执行,因此它将在需要时生成序列中的每个新元素,因此它只会生成您要求的任意数量的项目。如果你迭代五次,它只会产生A-E,并且不会在任何时候考虑接下来的事情而浪费。


1
投票

又一个发电机(将1添加到radix == 26的数字:A代表0,B代表1,... Z代表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();
  }
}

测试

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

结果

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

1
投票

你可以做这样的事情,它给你我的模式无穷无尽的输出(对不起,不完全你的模式,但你明白该怎么做)

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();
       }
    }
}

然后 :

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

编辑我有这个方法所需的输出:

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 "";
    }
 }

0
投票

你将要有一个从A到Z [A,...,Z]的数组。然后你要做多个for循环

例如:

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

0
投票

请尝试以下方法。这是一种为给定数字生成适当字符串的方法。您可以编写for循环,但需要多次迭代。

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;
}
© www.soinside.com 2019 - 2024. All rights reserved.