2012-03-09 51 views
1

我目前正在研究一個項目,我需要從給定的一組字符中生成所有可能的排列。我目前使用此代碼:使用相同字母的排列

public static IEnumerable<string> AllPermutations(this IEnumerable<char> s) 
{ 
    return s.SelectMany(x => 
    { 
     var index = Array.IndexOf(s.ToArray(), x); 
     return s.Where((y, i) => i != index).AllPermutations().Select(y => new string(new[] { x }.Concat(y).ToArray())).Union(new[] { new string(new[] { x }) }); 
    }).Distinct(); 
} 

this答案。

我遇到的問題是它不會生成多次使用相同字母的permuations。

例如,如果我用abcde作爲輸入我需要它像aaaaadcc

我沒有足夠的經驗與LINQ來理解代碼停止重複的字母組合產生。任何幫助是極大的讚賞。

+0

有什麼理由這樣做一個有趣的一個在LINQ中? – 2012-03-09 13:54:10

+0

我沒有寫這個,所以只是尋找真正做到這個工作的代碼。 – 2012-03-09 13:54:58

+1

'aaaaa'不是'abcde'的排列組合。如果你的項目需要排列不包括'aaaaa',如果你包含'aaaaa',不要把它稱爲排列(或者組合)。你只會混淆每個人閱讀你的問題,包括你自己。 – 2012-03-09 13:55:52

回答

3

威力工作,但我敢肯定,它可以更有效地進行(以計數提示從PeskyGnat):

static IEnumerable<string> GetVariations(string s) 
    { 
     int[] indexes = new int[s.Length]; 
     StringBuilder sb = new StringBuilder(); 

     while (IncrementIndexes(indexes, s.Length)) 
     { 
      sb.Clear(); 
      for (int i = 0; i < indexes.Length; i++) 
      { 
       if (indexes[i] != 0) 
       { 
        sb.Append(s[indexes[i]-1]); 
       } 
      } 
      yield return sb.ToString(); 
     } 
    } 

    static bool IncrementIndexes(int[] indexes, int limit) 
    { 
     for (int i = 0; i < indexes.Length; i++) 
     { 
      indexes[i]++; 
      if (indexes[i] > limit) 
      { 
       indexes[i] = 1; 
      } 
      else 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

編輯:更改爲使用收益率回報每羅林斯建議。如果您不需要保留所有結果,並且可以在全部生成結果之前開始使用結果,則可以更好地利用內存。

+0

這絕對是輝煌!我不能夠感謝你。 +1並接受,謝謝! – 2012-03-09 14:48:28

+0

無論這種做法是否可以更有效地完成,我相信它可以做得更低效。例如。我的回答:D – Rawling 2012-03-09 14:50:43

+0

@Rawling:其實我的一件事情不會這樣做,那就是處理重複。例如,如果字符串是「cca」,那麼我會兩次吐出「caa」,一次對於每個看起來不同的「c」。你們不這樣做。 – 2012-03-09 15:03:40

3

我很驚訝這個作品。它基本上是「從字符中創建一個字符串列表,然後對從列表中取出的每個字符串,再次添加每個字符,並將結果字符串添加到列表中,重複,直到得到正確的長度。

public static IEnumerable<string> BuildStrings(this IEnumerable<char> alphabet) 
{ 
    var strings = alphabet.Select(c => c.ToString()); 
    for (int i = 1; i < alphabet.Count(); i++) 
    { 
     strings = strings.Union(strings.SelectMany(s => alphabet.Select(c => s + c.ToString()))); 
    } 
    return strings; 
} 
+0

啊哈,它只會工作,因爲我在做'聯合'而不是'康卡特',否則我會有許多重複的... – Rawling 2012-03-09 15:12:29

0

通過固定點運營商只使用遞歸的lambda(THX @Rawling爲的SelectMany

// Fix point operator 
public static Func<T, TResult> Fix<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> f) 
    { 
     return t => f(Fix<T, TResult>(f))(t); 
    } 

然後

var chars = new[] {'a','b','c','d','e'}.Select(c=>c.ToString()) ; 

var result = Fix<int,IEnumerable<string>>(
    f => 
     x => 
     x == 1 
     ? chars 
     : chars.Union(f(x - 1).SelectMany(s => chars.Select(c => s + c))))(chars.Count());