【问题标题】:What's a good way for figuring out all possible words of a given length找出给定长度的所有可能单词的好方法是什么
【发布时间】:2010-09-23 16:29:01
【问题描述】:

我正在尝试在 C# 中创建一个算法,它产生以下输出字符串:

AAAA
AAAB
AAAC
...and so on...
ZZZX
ZZZY
ZZZZ

最好的方法是什么?

public static IEnumerable<string> GetWords()
{
    //Perform algorithm
    yield return word;
}

【问题讨论】:

  • 你想做什么?根据您的回答,懒惰地生成列表可能会更好。
  • @John the Statistician:使用迭代器块确实会延迟生成列表。
  • 这在创建幼稚的蛮力逻辑时很有用。我曾经在课堂上做过类似的事情,我们不得不破解一个密码。分析技术很简单,所以我还编写了一个程序,在一个星期六早上的几个小时内使用了整个大学计算机实验室。 :)

标签: c# string algorithm iterator


【解决方案1】:

好吧,如果长度是常数 4,那么它会处理它:

public static IEnumerable<String> GetWords()
{
    for (Char c1 = 'A'; c1 <= 'Z'; c1++)
    {
        for (Char c2 = 'A'; c2 <= 'Z'; c2++)
        {
            for (Char c3 = 'A'; c3 <= 'Z'; c3++)
            {
                for (Char c4 = 'A'; c4 <= 'Z'; c4++)
                {
                    yield return "" + c1 + c2 + c3 + c4;
                }
            }
        }
    }
}

如果长度是一个参数,这个递归解决方案会处理它:

public static IEnumerable<String> GetWords(Int32 length)
{
    if (length <= 0)
        yield break;

    for (Char c = 'A'; c <= 'Z'; c++)
    {
        if (length > 1)
        {
            foreach (String restWord in GetWords(length - 1))
                yield return c + restWord;
        }
        else
            yield return "" + c;
    }
}

【讨论】:

  • 当我看到第一个提案中的样板时,我几乎不赞成。第二个似乎还可以。
【解决方案2】:

总是有强制性的 LINQ 实现。很可能是垃圾性能,但从什么时候开始,性能阻碍了使用很酷的新功能?

var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();

var sequence = from one in letters
               from two in letters
               from three in letters
               from four in letters
               orderby one, two, three, four
               select new string(new[] { one, two, three, four });

'sequence' 现在将是一个包含 AAAA 到 ZZZZ 的 IQueryable。

编辑:

好的,所以让我感到困扰的是,应该可以使用 LINQ 使用可配置的字母表制作可配置长度的序列。所以就在这里。再一次,完全没有意义,但它困扰着我。

public void Nonsense()
{
    var letters = new[]{"A","B","C","D","E","F",
                        "G","H","I","J","K","L",
                        "M","N","O","P","Q","R","S",
                        "T","U","V","W","X","Y","Z"};

    foreach (var val in Sequence(letters, 4))
        Console.WriteLine(val);
}

private IQueryable<string> Sequence(string[] alphabet, int size)
{
    // create the first level
    var sequence = alphabet.AsQueryable();

    // add each subsequent level
    for (var i = 1; i < size; i++)
        sequence = AddLevel(sequence, alphabet);

    return from value in sequence
           orderby value
           select value;
}

private IQueryable<string> AddLevel(IQueryable<string> current, string[] characters)
{
    return from one in current
           from character in characters
           select one + character;
}

对 Sequence 方法的调用生成与以前相同的 AAAA 到 ZZZZ 列表,但现在您可以更改使用的字典以及生成的单词的长度。

【讨论】:

  • 如果该解决方案是正确的,它就是一个了不起的解决方案。感谢您的 C# 洞察力。当他写关于元编程的 C# 5.0 时,我必须买一本 jon skeet 书 :)
【解决方案3】:

只是对 Garry Shutler 的评论,但我想要代码着色:

你真的不需要让它 IQuaryable,排序也不需要,所以你可以删除第二种方法。向前迈出的一步是使用 Aggregate 作为叉积,它最终是这样的:

IEnumerable<string> letters = new[]{
                "A","B","C","D","E","F",                       
                "G","H","I","J","K","L",
                "M","N","O","P","Q","R","S",           
                "T","U","V","W","X","Y","Z"};

var result = Enumerable.Range(0, 4)
                .Aggregate(letters, (curr, i) => curr.SelectMany(s => letters, (s, c) => s + c));

foreach (var val in result)
     Console.WriteLine(val);

安德斯应该因为 Linq 的事情获得诺贝尔奖!

【讨论】:

    【解决方案4】:

    GNU 重击!

    {a..z}{a..z}{a..z}{a..z}
    

    【讨论】:

      【解决方案5】:

      Python!

      (这只是一个 hack,别把我当回事 :-)

      # Convert a number to the base 26 using [A-Z] as the cyphers
      def itoa26(n): 
         array = [] 
         while n: 
            lowestDigit = n % 26
            array.append(chr(lowestDigit + ord('A'))) 
            n /= 26 
         array.reverse() 
         return ''.join(array)
      
      def generateSequences(nChars):
         for n in xrange(26**nChars):
            string = itoa26(n)
            yield 'A'*(nChars - len(string)) + string
      
      for string in generateSequences(3):
         print string
      

      【讨论】:

        【解决方案6】:

        受到 Garry Shutler 回答的启发,我决定用 T-SQL 重新编码他的回答。

        假设“Letters”是一个只有一个字段 MyChar 和 CHAR(1) 的表。它有 26 行,每行一个字母。所以我们就有了(您可以将此代码复制粘贴到 SQL Server 上并按原样运行以查看它的实际效果):

        DECLARE @Letters TABLE (
            MyChar CHAR(1) PRIMARY KEY
        )
        DECLARE @N INT
        SET @N=0
        WHILE @N<26 BEGIN
            INSERT @Letters (MyChar) VALUES ( CHAR( @N + 65) )
            SET @N = @N + 1
        END
        -- SELECT * FROM @Letters ORDER BY 1
        
        SELECT A.MyChar, B.MyChar, C.MyChar, D.MyChar
        FROM @Letters A, Letters B, Letters C, Letters D
        ORDER BY 1,2,3,4
        

        优点是:它很容易扩展到使用大写/小写,或使用非英语拉丁字符(想想“Ñ”或 cedille、eszets 等),你仍然会得到一个有序的集合,只需要添加排序规则。此外,SQL Server 在单核机器上的执行速度将比 LINQ 稍快,在多核(或多处理器)上,执行可以并行执行,从而获得更大的提升。

        不幸的是,它被卡在 4 个字母的特定大小写上。 lassevk 的递归解决方案更通用,尝试在 T-SQL 中做通用解决方案必然意味着动态 SQL 及其所有危险。

        【讨论】:

        • 你无法击败haskell:print [ a:b:c:d:[] |让 q = ['a' .. 'z'], a
        • @Joe Pineda 您的解决方案将永远不会生成 DCBA,因为“ORDER BY 1,2,3,4”
        • 是的!我刚刚通过在 SQL S 2000 上运行代码进行了检查:序列“DCBA”是第 54107 行。确实产生了所有可能的组合,我正在扩展代码以便更容易测试。
        【解决方案7】:

        哈斯克尔!

        replicateM 4 ['A'..'Z']
        

        鲁比!

        ('A'*4..'Z'*4).to_a
        

        【讨论】:

          【解决方案8】:

          更简单的 Python!

          def getWords(length=3):
              if length == 0: raise StopIteration
              for letter in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
                  if length == 1: yield letter
                  else:
                      for partialWord in getWords(length-1):
                          yield letter+partialWord
          

          【讨论】:

            【解决方案9】:

            这是 C# 中相同函数的递归版本:

            using System;
            using System.Collections.Generic;
            using System.Text;
            using System.IO;
            
            namespace ConsoleApplication1Test
            {
                class Program
                {
                    static char[] my_func( char[] my_chars, int level)
                    {
                        if (level > 1)
                            my_func(my_chars, level - 1);
                        my_chars[(my_chars.Length - level)]++;
                        if (my_chars[(my_chars.Length - level)] == ('Z' + 1))
                        {
                            my_chars[(my_chars.Length - level)] = 'A';
                            return my_chars;
                        }
                        else
                        {
                            Console.Out.WriteLine(my_chars);
                            return my_func(my_chars, level);
                        }
                    }
                    static void Main(string[] args)
                    {
                        char[] text = { 'A', 'A', 'A', 'A' };
                        my_func(text,text.Length);
                        Console.ReadKey();
                    }
                }
            }
            

            从 AAAA 打印到 ZZZZ

            【讨论】:

              【解决方案10】:

              javascript!

              var chars = 4, abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", top = 1, fact = [];
              for (i = 0; i < chars; i++) { fact.unshift(top); top *= abc.length; }
              for (i = 0; i < top; i++)
              {
                  for (j = 0; j < chars; j++) 
                      document.write(abc[Math.floor(i/fact[j]) % abc.length]);
                  document.write("<br \>\n");
              }
              

              【讨论】:

              • 很好,所以您首先要计算顶部可能出现的单词数。并且您正在将字符视为基数 abc.length 中的数字 :) 我前段时间想到了,这是一个好主意 :) 并且比递归方法更好,尽管除法和模数可能会造成损失
              【解决方案11】:

              使用自动谷歌搜索每个字母组合的东西,然后查看是否有更多的“.sz”或“.af”点击然后“.com”点击五个第一个结果......;)

              说真的,您正在寻找的可能是 Tries(数据结构),尽管您仍然需要填充可能更难的东西......

              【讨论】:

                【解决方案12】:

                一个非常简单但很棒的代码,可以生成所有 3 和 4 个英文字母的单词

                #include <iostream>
                using namespace std;
                char alpha[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}
                int main() {
                int num;
                cin >> num;
                if (num == 3) { //all 3 letter words
                    for (int i = 0; i <= 25; i++) {
                        for (int o = 0; o <= 25; o++) {
                            for (int p = 0; p <= 25; p++) {
                                cout << alpha[i] << alpha[o] << alpha[p] << " ";
                            }
                        }
                    }
                }
                else if (num == 4) { //all 4 letter words
                    for (int i = 0; i <= 25; i++) {
                        for (int o = 0; o <= 25; o++) {
                            for (int p = 0; p <= 25; p++) {
                                for (int q = 0; q <= 25; q++) {
                                    cout << alpha[i] << alpha[o] << alpha[p] << alpha[q] << " ";
                                }
                            }
                        }
                    }
                }
                else {
                    cout << "Not more than 4"; //it will take more than 2 hours for generating all 5 letter words
                  }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-12-14
                  • 2019-12-08
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-22
                  • 1970-01-01
                  相关资源
                  最近更新 更多