【问题标题】:String generator issue字符串生成器问题
【发布时间】:2013-06-26 15:46:19
【问题描述】:

我想写一个返回字符串的方法。到目前为止,一切都很好。然而,字符串的创建相当复杂。我有 3 个字符串列表 - 第一个有 155 个条目,第二个有 9 个,第三个有 21 个。我希望我的方法调用足够多的次数(155*9*21)来返回 3 中所有可能的值组合列表(基本上这个方法应该计算它被调用的次数并且每次只返回一个组合)。任何想法如何做到这一点?

我有 155*9*22 种可能的组合。第一次调用该方法时,它应该采用 List1(0)、List2(0)、List3(0)。之后在接下来的 21 次迭代中,仅更改了第三个列表的索引。一旦第三个列表中的所有元素都被使用,第二个列表的索引就会增加,依此类推。

一旦方法产生了所有可能的组合 (155*9*22),我希望它从头开始。

【问题讨论】:

  • 也许你应该试试yield return :example
  • 简单到三个for循环;为每个循环中的每个单词打印结果

标签: c# string list random


【解决方案1】:

你可以列举所有可能的组合,像这样:

    public IEnumerable<String> generator() {
      foreach (String item1 in List1)
        foreach (String item2 in List2)
          foreach (String item3 in List3)
            yield return item1 + item2 + item3;
    }

   ...

   foreach (String item in generator()) {
     // Do something with generated strings
   }

【讨论】:

  • 是的,但字符串的生成应该只在调用该方法时发生,我的目标是使用一些索引来保持我在同一个方法中的距离。
  • @Andrey 阅读了我在 cmets 中针对您的问题发布的链接
  • 是的,这将返回所有可能的组合。但是,我希望我的方法仅在调用它时进行计算,并继续计算它走了多远。一种可能的方法是获取所有组合并为它们编制索引,但如果我决定扩展该方法(添加一个更多列表),那么这将导致大量结果,这是不必要的内存使用。
  • @Andrey:这不会生成单独的列表。它根据需要一次返回一个项目。这就是延迟执行的意义(除其他外)。您可以使用我在答案中发布的技术来跟踪计数。
  • @Dmitry:如果你喜欢,你可以把我的答案和你的结合起来,我会删除我的答案。
【解决方案2】:

使用良好的旧模运算符。可能还可以优化很多。

public class Generator
{
    private int index = 0;
    private List<string> list1 = new List<string> { "a", "b" };
    private List<string> list2 = new List<string> { "c", "d" };
    private List<string> list3 = new List<string> { "e", "f", "g" };

    public string Next()
    {
        int indexList3 = index % list3.Count;
        int indexList2 = (index / list3.Count) % list2.Count;
        int indexList1 = (index / (list2.Count * list3.Count)) % list1.Count;

        IncrementIndex();

        return list1[indexList1] + list2[indexList2] + list3[indexList3];
    }

    private void IncrementIndex()
    {
        index++;
        if (index > list1.Count*list2.Count*list3.Count)
        {
            index = 0;
        }
    }
}

所以前 13 个结果(关于 12 种可能的组合),用

获得
string result = string.Empty;
Generator generator = new Generator();

for (int i = 0; i < 13; i++)
{
    result += generator.Next() + "\n";
}

输出:

ace
acf
acg
ade
adf
adg
bce
bcf
bcg
bde
bdf
bdg
ace

【讨论】:

    【解决方案3】:

    您可以为每个列表保留一个索引:

    public IEnumerable<string> Permutations(string[][] lists, int start = 0) {
        int[] position = new int[lists.Length];
    
        for(int i = lists.Length - 1; start > 0; i--) {
            position[i] = start % lists[i].Length;
            start /= lists[i].Length;
        }
    
        while(true) {
            int i;
            string current = string.Empty;
    
            for(i = lists.Length - 1; i >= 0; i--) {
                if(++position[i] == lists[i].Length) {
                    position[i] = 0;
                    current = lists[i][0] + current;
                } else {
                    break;
                }
            }
    
            if(i == -1) break;
    
            while(i > -1) {
                current = lists[i][position[i]] + current;
                i--;
            }
    
            yield return current;
        }
    }
    

    它需要一个开始的地方,可选地,因此您可以只保留一个整数并生成下一项。

    不过,我还没有测试过。被警告! :)

    【讨论】:

      【解决方案4】:

      使用Dmitry Bychenko显示的方法,您可以跟踪您在列表中的位置:

      // use his generator method
      public IEnumerable<String> generator()
      {
          ...
      }
      
      ....
      
      int counter = 0;
      foreach (String item in generator())
      {
          // compute indexes
          int ix_list3 = counter % List3.Count;
          int ix_list2 = (counter / List3.Count) % List2.Count;
          int ix_list1 = (counter / (List3.Count * List2.Count));
      
          // do something with item and indexes
          ++counter;
      }
      

      【讨论】:

        【解决方案5】:
        public IEnumerable<string> List1 = new [] { "A", "B", "C" };
        public IEnumerable<string> List2 = new [] { "1", "2", "3" };
        public IEnumerable<string> List3 = new [] { "Z", "Y" };
        
        public IEnumerator<string> StringEnumerator;
        
        public void InitializeEnumerator()
        {
            var stringEnumerable = List1.SelectMany(x => List2.SelectMany(y => List3.Select(z => x + y + z)));
        
            StringEnumerator = stringEnumerable.GetEnumerator();
        }
        
        public string GetNextString()
        {
            return StringEnumerator.MoveNext() ? StringEnumerator.Current : null;
        }
        

        只需调用 InitializeEnumerator(),然后每次调用 GetNextString() 都会得到一个新字符串

        InitializeEnumerator();
        GetNextString(); //-> A1Z
        GetNextString(); //-> A1Y
        GetNextString(); //-> A2Z
        GetNextString(); //-> A2Y
        GetNextString(); //-> A3Z
        GetNextString(); //-> A3Y
        GetNextString(); //-> B1Z
        

        要让它自动初始化并在它用完后重新初始化,像这样修改 GetNextString。

        public string GetNextString()
        {
            if(StringEnumerator == null || !StringEnumerator.MoveNext())
            {
                InitializeEnumerator();
                StringEnumerator.MoveNext();
            }
        
            return StringEnumerator.Current;
        }
        

        【讨论】:

        • 一旦涵盖了所有组合,如何让它从第一个开始迭代?
        • 再次调用 InitializeEnumerator() 即可。
        • 我修改了答案以包含 GetNextString 的循环版本
        猜你喜欢
        • 2014-01-04
        • 1970-01-01
        • 1970-01-01
        • 2016-08-03
        • 2014-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多