次の出力文字列を生成するアルゴリズムを C# で作成しようとしています。
AAAA
AAAB
AAAC
...and so on...
ZZZX
ZZZY
ZZZZ
これを達成するための最良の方法は何ですか?
public static IEnumerable<string> GetWords()
{
//Perform algorithm
yield return word;
}
長さが定数 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;
}
}
必ず必須の 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 へのリストが生成されますが、使用する辞書と、生成される単語の長さを変更できるようになりました。
Garry Shutler へのコメントですが、コードの色付けが必要です。
IQuaryable にする必要もソートする必要もないので、2 番目のメソッドを削除できます。一歩前進することは、外積に 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 のことでノーベル賞を受賞するべきです!
GNUバッシュ!
{a..z}{a..z}{a..z}{a..z}
もっと簡単なパイソン!
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
Garry Shutler の回答に触発されて、T-SQL で彼の回答を再コーディングすることにしました。
「Letters」は、1 つのフィールド、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
利点は次のとおりです。大文字/小文字の使用、または英語以外のラテン文字 (「Ñ」またはセディーユ、エスゼットなどを考えてください) の使用に簡単に拡張でき、照合を追加するだけで順序付きセットを取得できます。 . さらに、SQL Server はシングル コア マシン上でこれを LINQ よりもわずかに高速に実行します。
残念ながら、4 文字の特定のケースでスタックしています。lassevk の再帰的な解決策はより一般的です。T-SQL で一般的な解決策を実行しようとすると、必然的にすべての危険を伴う動的 SQL が暗示されます。
パイソン!
(これは単なるハックです。あまり真剣に考えないでください :-)
# 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
ハスケル!
replicateM 4 ['A'..'Z']
ルビー!
('A'*4..'Z'*4).to_a
これは、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 までを印刷します。
ジャバスクリプト!
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");
}
すべての文字の組み合わせに対して自動的にグーグル検索するものを使用し、「.sz」または「.af」のヒットがさらにあるかどうかを確認し、最初の 5 つの結果で「.com」のヒットがあるかどうかを確認します ... ;)
真剣に、あなたが探しているのは Tries (データ構造) かもしれませんが、おそらくはるかに難しいものを設定する必要があります...