2015-08-20 37 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