2017-06-03 117 views
0

我在C#中看到了幾個字符串變體的實現,但它們都沒有對它們的長度有任何限制。不幸的是,我無法修改它們來實現我的目標,例如從字符串中生成特定長度的所有變體

爲:

string = "ABCD" and variationLength = 2 

生成新的字符串:

AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC 

我正在尋找的正是這種Python的和itertools.permutations實現,但在C#。 (https://docs.python.org/3/library/itertools.html#itertools.permutations

在C#中有類似的東西嗎?如果不是,那麼實現它的最簡單方法是什麼?

Edit_2: 到目前爲止,我想出了一個主意,列出定字符串的所有獨特的字符,然後讓變化了出來

static void PrintAllKLengthPerm(string str, int k) 
{ 
    int n = str.Length; 
    PrintAllKLengthPermRec(str, "", n, k); 
} 

// The main recursive method to print all possible strings of length k 
static void PrintAllKLengthPermRec(string str, String prefix, int n, int k) 
{ 
    // Base case: k is 0, print prefix 
    if (k == 0) 
    { 
     Console.WriteLine(prefix); 
     return; 
    } 

    // One by one add all characters from str and recursively 
    // call for k equals to k-1 
    for (int i = 0; i < n; ++i) 
    { 
     // Next character of input added 
     String newPrefix = prefix + str[i]; 

     // k is decreased, because we have added a new character 
     PrintAllKLengthPermRec(str, newPrefix, n, k - 1); 
    } 
} 

static void Main(string[] args) 
{ 
    string str = "ABCD"; 
    int permLen = 2; 

    //get all unique characters in string 
    string uniqStr = new String(str.Distinct().ToArray()); 

    // Print all possible strings of length permLen out of uniqStr characters 
    PrintAllKLengthPerm(uniqStr, permLen);  
} 

但是我正在尋找更優化,有效地解決

+2

你嘗試過這麼遠嗎? – Ani

+0

請顯示您的工作。你試過什麼了? – Soviut

+0

@Soviut編輯.. –

回答

1

這裏是一個真正的遞歸排列法:

public IEnumerable<string> Permutate(string source, int count) 
{ 
    if (source.Length == 1) 
    { 
     yield return source; 
    } 
    else if (count == 1) 
    { 
     for (var n = 0; n < source.Length; n++) 
     { 
      yield return source.Substring(n, 1); 
     } 
    } 
    else 
    { 
     for (var n = 0; n < source.Length; n++) 
      foreach (var suffix in Permutate(
       source.Substring(0, n) 
        + source.Substring(n + 1, source.Length - n - 1), count -1)) 
      { 
       yield return source.Substring(n, 1) + suffix; 
      } 
    } 
} 

它可與Permutate("ABCD", 2)被調用,返回此:

output

1
List<string> newPermutations = new List<string>(); 
for(int a = 0; a!=inString.Count; a++) 
    for((int b = 0; b!=inString.Count; b++) 
     if(noRepetitions && a == b) continue; 
     newPermutations.Add(""+inString[a] + inString[b]); 

我認爲這應該工作;我仍然試圖找出一種不僅有2個字母的方法。

編輯:編輯它的工作,舊的只是沒有工作...笑 編輯:感謝@Bloopy,他們幫助我發現在我的for循環

+0

要有一個可以更改的'permutationLength'變量,也許你可以看看創建一個沒有的數組。的尺寸,然後循環這些。但有兩點:如果您將'foreach'改爲'for'並使用ints'i'&'j'(檢查'i!= j'),那麼您的解決方案將適用於具有重複元素的字符串排列。此外,您需要將'a'轉換爲字符串,作爲字符的'a + b'添加其整數值。 – Bloopy

+0

@Bloopy 1.如何選擇多個維度......我之前曾經考慮過這個問題,但一個想法從來沒有出現過(我也沒有做過任何真正的研究。)2.「我」 j'方法是一個好主意,並且3.'「」+ a + b'會起作用。感謝您的改進! –

+0

我對它進行了更多的研究,並意識到它會比我現有的答案更加複雜。但是,我確實找到了一種使用LINQ的替代方法,我已經添加了它作爲替代方法。順便說一下,你忘了增加你的變量,你已經添加了3個更多的編譯錯誤到你的代碼! – Bloopy

1

我做了下面的遞歸一些錯誤功能,完成你的任務:

static void Permutations(List<string> output, string str, int n, string curr) 
    { 
     if(curr.Length == n) 
     { 
      output.Add(curr); 
      return; 
     } 
     foreach(char c in str) 
      if(!curr.Contains(c.ToString())) 
       Permutations(output, str, n, curr + c.ToString()); 
    } 

然後調用它像這樣:

string str = "ABCD"; 
int length = 2; 
List<string> perms = new List<string>(); 
Permutations(perms, str, length, ""); 
// now the list "perms" will contain the permutations of "str" in length "n" 
0

下面是使用模和除法的解決方案。有4個可能的長度爲2的字符串,使用字母ABCD。將它們編號從0到4 2 -1,並將每個數字重複除以4.將所得的餘數用作ABCD字符串上的數組索引。

這有讓您保持琴絃與重複的元素(AA,BB,CC,DD)在需要時的優勢 - 只是跳過丟棄步驟。

string alphabet = "ABCD"; 
int length = 2; 

int[] indexes = new int[length]; 
char[] item = new char[length]; 

// loop through all possible strings for the given alphabet and length 
for (int i = 0; i < Math.Pow(alphabet.Length, length); i++) { 

    int dividend = i; 
    for (int j = length - 1; j >= 0; j--) { 
     indexes[j] = dividend % alphabet.Length; 
     dividend /= alphabet.Length; 
    } 

    // discard any that use the same alphabet element more than once 
    if (indexes.Distinct().Count() < length) 
     continue; 

    for (int k = 0; k < length; k++) { 
     item[k] = alphabet[indexes[k]]; 
    } 

    Console.WriteLine(item); 
} 

另外,這裏是一個非常簡單的使用LINQ的解決方案。請注意,如果字符串中存在重複的元素,則不能正確工作(除非您想要移除對Where的呼叫並保留AA,BB等)。我需要像上面我的方法那樣跟蹤索引。

IEnumerable<string> prm = alphabet.Select(c => c.ToString()); 
for (int a = 1; a < length; a++) 
    prm = prm.SelectMany(s => alphabet.Where(t => !s.Contains(t)), (x, y) => x + y); 

foreach (string s in prm) 
    Console.WriteLine(s); 
相關問題