2009-12-14 62 views
4

可能重複:
C#: Is using Random and OrderBy a good shuffle algorithm?收集隨機使用擴展方法

我想創建應洗牌集合中的項目的擴展方法。

我可以改進以下嗎?

public static IList<T> RandomList<T>(this IList<T> source) 
{ 
    if (source.Count <= 0) throw new ArgumentException("No Item to Randomize"); 

      for (int i =source.Count-1 ; i>0; i--) 
      { 
       int RandomIndex = Rnd.Next(i + 1); 
       T temp = source[i]; 
       source[i] = source[RandomIndex]; 
       source[RandomIndex] = temp; 
      } 

      return source; 
} 
+0

是的,看到http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm – jason 2009-12-14 15:36:25

+0

那沒有資格作爲一個確切的重複。 – 2009-12-14 15:42:35

+0

@C。羅斯:看看喬恩的回答。它回答了這個問題。 – jason 2009-12-14 15:52:36

回答

1

有幾個問題,我會用這種方法:

  • 應該檢查空的論點。
  • 它不應該檢查一個0長度的列表。
  • 避免副作用。爲混洗元素創建一個新列表,而不是修改現有的元素。
  • 不要隱藏依賴關係。將隨機數生成器作爲參數傳遞。
  • 使用比'RandomList'更具描述性的名稱。
  • 輸入類型可以概括爲IEnumerable。
  • 該方法可以更改爲枚舉器[概括輸出類型]。

本質:

public static IList<T> Shuffled<T>(this IEnumerable<T> source, Random generator) 
{ 
    if (source == null) throw new ArgumentNullException("source"); 
    if (generator == null) throw new ArgumentNullException("generator"); 

    //copy 
    var result = source.ToList(); 
    //shuffle the copy 
    for (int i = result.Count - 1; i > 0; i--) 
    { 
     int RandomIndex = generator.Next(i + 1); 
     T temp = result[i]; 
     result[i] = result[RandomIndex]; 
     result[RandomIndex] = temp; 
    } 

    return result; 
} 

我沒有一概而論的輸出類型。你可以做到這一點,如果你想。

1

我覺得已經足夠好,只要你知道Random is not very random.

Random類是存活在簡單的遊戲和其他非科學領域的應用。不要將其用於密碼學。

+0

「隨機」意味着(幾乎)所有的意圖和目的是隨機的。 – jason 2009-12-14 16:14:06

+0

比對不起更安全。 – 2009-12-14 16:27:39

0

使它返回本身有點多餘。如果您要返回列表的深層副本,當然;在這種情況下,它應該被稱爲「GetShuffledCopy()」或類似的東西。如果你表現的名單本身,它應該是一個void返回和被稱爲像「隨機播放()」

-Oisin

1

一般來說,你應該避免更改列表,而是返回一個新的列表。更好的辦法是返回IEnumerable以與其他擴展方法和LINQ保持一致。

試試這個。

public static class RandomizeExtensionMethods 
{ 
    private static readonly Random _random = new Random(); 

    public static IEnumerable<T> Randomize<T>(this IList<T> enumerable) 
    { 
     if (enumerable == null || enumerable.Count == 0) 
     { 
      return new List<T>(0); 
     } 

     return RandomizeImpl(enumerable);   
    } 

    public static IEnumerable<T> RandomizeImpl<T>(this IList<T> enumerable) 
    { 
     var indices = new int[enumerable.Count]; 
     for(int i=0; i<indices.Length; i++) 
     { 
      indices[i] = i; 
     } 

     lock (_random) 
     { 
      for (int i = 0; i < indices.Length - 1; i++) 
      { 
       int j = _random.Next(i, indices.Length); 
       int swap = indices[j]; 
       indices[j] = indices[i]; 
       indices[i] = swap; 
      } 
     } 

     for(int i=0; i<indices.Length; i++) 
     { 
      yield return enumerable[indices[i]]; 
     } 
    } 
} 
+0

不錯的實施@Sam。如果元素的拷貝成本很高,我喜歡先行考慮交換標記而不是元素本身。 – 2010-06-09 01:36:04

5
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) 
{ 
    foreach(var item in source.OrderBy(i => Guid.NewGuid())) 
    { 
     yield return item; 
    } 
}