2015-08-20 45 views
-1

我想使用fisher-yates shuffle洗牌列表中的元素。但是,除非我在它應該洗牌的地方設置斷點,否則這些元素似乎不會洗牌。我嘗試異步執行洗牌,但我沒有運氣(也許我做錯了)。IEnumerable不會洗牌,除非我把一個斷點

洗牌算法如下:

// Uses Fisher-Yates shuffle to swap elements 
    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) 
    { 
     Random rng = new Random(); 
     T[] elements = source.ToArray(); 

     for (int i = elements.Length - 1; i >= 0; i--) 
     { 
      int j = rng.Next(i + 1); 
      yield return elements[j]; 
      elements[j] = elements[i]; 
     } 

    } 

我洗牌是這樣的:

imageDataList= imageDataList.Shuffle().ToList(); 

我異步洗牌是這樣的:

imageDataList = await Task.Run(() => imageDataList.Shuffle().ToList()); 

這裏是我的代碼片段:

GameData gameData = null; 
ImageData imageData = null; 
ToneData toneData = null; 
ImageToneData imageToneData = null; 
LevelData levelData = null; 

List<ImageData> imageDataList = new List<ImageData>(); 
List<ToneData> toneDataList = new List<ToneData>(); 
List<ImageToneData> imageToneDataList = new List<ImageToneData>(); 
List<LevelData> levelDataList = new List<LevelData>(); 

// Add images to a list of ImageData contracts 
    foreach (GameImage gameImage in game.GameImages) 
    { 
     imageData = new ImageData() 
     { 
      ImageId = gameImage.Image.ImageId, 
      ImageFileName = gameImage.Image.ImageFileName 
     }; 

     imageDataList.Add(imageData); 

    } 

    // Add tones to a list of ToneData contracts 
    foreach (GameTone gameTone in game.GameTones) 
    { 
     toneData = new ToneData() 
     { 
      ToneId = gameTone.Tone.ToneId, 
      ToneFileName = gameTone.Tone.ToneFileName 
     }; 

     toneDataList.Add(toneData); 
    } 


    //Randomize image and tone association 
    imageDataList = imageDataList.Shuffle().ToList(); 
    toneDataList = toneDataList.Shuffle().ToList(); 

    // Combine imageData and toneData and assign a position 
    for (int i = 0; i < game.NumLevels; i++) 
    { 
     imageToneData = new ImageToneData() 
     { 
      Image = imageDataList.ElementAt(i), 
      Tone = toneDataList.ElementAt(i), 
      Position = (i + 1) 
     }; 

     imageToneDataList.Add(imageToneData); 

    } 

    foreach (GameLevel level in game.GameLevels) 
    { 
     //Randomize image/tone (already fixed association) 
     imageToneDataList = imageToneDataList.Shuffle().ToList(); 

     levelData = new LevelData() 
     { 
      GameLevelId = level.GameLevelId, 
      Level = level.Level, 
      UniqueRounds = level.UniqueRounds, 
      Rounds = level.Rounds, 
      NumImages = level.NumImages, 
      ImageTones = imageToneDataList.Take(level.NumImages) 
     }; 

     levelDataList.Add(levelData); 
    } 

gameData = new GameData() 
{ 
    NumLevels = game.NumLevels, 
    SelectionTime = game.SelectionTime, 
    Levels = levelDataList 
}; 

我的數據合同如下:

[DataContract] 
    public class GameData 
    { 
     [DataMember] 
     public int NumLevels { get; set; } 

     [DataMember] 
     public int? SelectionTime { get; set; } 

     [DataMember] 
     public IEnumerable<LevelData> Levels { get; set; } 
    } 

[DataContract] 
public class LevelData 
{ 
    [DataMember] 
    public int GameLevelId { get; set; } 

    [DataMember] 
    public int Level { get; set; } 

    [DataMember] 
    public bool UniqueRounds { get; set; } 

    [DataMember] 
    public int Rounds { get; set; } 

    [DataMember] 
    public int NumImages { get; set; } 

    [DataMember] 
    public IEnumerable<ImageToneData> ImageTones { get; set; } 

} 


[DataContract] 
public class ImageToneData 
{ 
    [DataMember] 
    public ImageData Image { get; set; } 

    [DataMember] 
    public ToneData Tone { get; set; } 

    [DataMember] 
    public int? Position { get; set; } 

} 


[DataContract] 
public class ImageData 
{ 
    [DataMember] 
    public int ImageId { get; set; } 

    [DataMember] 
    public string ImageFileName { get; set; } 
} 


[DataContract] 
public class ToneData 
{ 

    [DataMember] 
    public int ToneId { get; set; } 

    [DataMember] 
    public string ToneFileName { get; set; } 
} 

任何幫助,非常感謝!

+0

將代碼放置在一個空的控制檯項目中。問題仍然存在嗎?它不會。 – usr

+0

嘗試將'elements'列爲一個列表,並在每次產生列表時刪除它們。 –

+0

@usr我有一個單獨的項目中的代碼在一個單獨的項目 –

回答

2

我的猜測是,這兩個名單,imageDataListtoneDataList,實際被打亂。我懷疑他們看起來並沒有被洗牌,因爲每次運行代碼時,當您將兩個列表合併到imageToneDataList中時,相同的色調會與上次運行代碼時的相同圖像保持配對。這是因爲每次調用時,您的Shuffle方法都會實例化一個新的RandomRandom使用系統時鐘來產生其種子。所以如果你實例化兩個Random對象(比如你連續兩次調用Shuffle),他們會有相同的種子。這意味着他們會產生相同的隨機數字。這意味着您的兩個列表正在按照完全相同的順序進行混洗。這解釋了爲什麼當你只洗一個列表時,它看起來工作正常。當您將混洗列表與未混入imageToneDataList的列表結合時,您會得到您期望的隨機結果。這也解釋了爲什麼它在您使用中斷點時有效。它們在您第一次撥打電話Shuffle和第二次足夠長時間以創建帶有新種子的Random對象之間延遲。

要獲得您期望的行爲,您需要有一個Random的實例 - 也許是包含您的擴展方法的類中的靜態字段。

+0

這非常有意義非常感謝你! –

+0

很高興我能幫到你。我自己被「Random」絆倒了。 –

-1

我的方法改變這樣的事情:

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source) 
{ 
    Random rng = new Random(); 
    List<T> elements = source.ToList(); 

    while (elements.Count > 0) 
    { 
     int i = rng.Next(elements.Count); 
     T item = elements[i]; 
     elements.RemoveAt(i); 
     yield return item; 
    } 
} 
+0

這只是OP解決方案的嚴格更糟糕的版本。 – Servy

+0

你能定義爲什麼嗎?我只是好奇 –

+0

我已經有了以上。我完全一樣,只是速度較慢,並不能解決OP在程序中遇到的問題。正如幾個人已經說過的,OP的這種方法的實現非常好。 – Servy