随机化列表,但有范围

时间:2017-06-22 09:34:22

标签: c# list xamarin random xamarin.forms

我有一个包含72个项目的列表。该程序有点像Tinder,其中显示了图片和一些文字。

我希望这个List是随机的,而不是第一张"卡"和最后一张"卡"例如。 item no. 1 & item no. 72这些必须保留为第一张和最后一张卡,其余70件将按随机顺序排序。

这是我的代码片段,我在其中定义了列表

public class MainPageViewModel : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;

   List<CardStackView.Item> items = new List<CardStackView.Item>();
   public List<CardStackView.Item> ItemsList
   {
      get { return items; }
      set { if (items == value) { return; } items = value; OnPropertyChanged(); }
   }

   protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
   {
      PropertyChangedEventHandler handler = PropertyChanged;
      if(handler != null)
      {
         handler(this, new PropertyChangedEventArgs(propertyName));
      }
   }

   protected virtual void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
   {
      field = value;
      PropertyChangedEventHandler handler = PropertyChanged;
      if(handler != null)
      {
         handler(this, new PropertyChangedEventArgs(propertyName));
      }
   }

   public MainPageViewModel()
   {
      items.Add(new CardStackView.Item() { Name = "xxxx", Photo = new Uri("yyyy"), Description = "zzzz", ID = 1 });
      items.Add(new CardStackView.Item() { Name = "xxxx", Photo = new Uri("yyyy"), Description = "zzzz", ID = 2 });
      items.Add ........
      items.Add(new CardStackView.Item() { Name = "xxxx", Photo = new Uri("yyyy"), Description = "zzzz", ID = 72 });
   }
}

当它们都在一个列表中时,我可以这样做,还是应该创建一个多维数组。索引1为item no. 1,索引2为Randomized List&amp;索引3是item no. 72。如果这是一个正确的解决方案,我将如何在我的卡片上显示它们。

我一直在研究像这些问题Randomize a List<T>&amp; Best way to randomize an array with .NET,但我没有成功。

3 个答案:

答案 0 :(得分:1)

很容易让a standard random shuffle algorithm适应接受起始索引和计数:

public static void Shuffle<T>(IList<T> array, Random rng, int first, int count)
{
    for (int n = count; n > 1;)
    {
        int k = rng.Next(n);
        --n;
        T temp = array[n+first];
        array[n + first] = array[k + first];
        array[k + first] = temp;
    }
}

然后,如果你想要洗掉除了第一个和最后一个项目之外的所有项目:

Shuffle(items, new Random(), 1, items.Count-2);

答案 1 :(得分:0)

试试这个:

private Random random = new Random();

public MainPageViewModel()
{
    /* Populate `items` */

    items =
        items
            .Take(1)
            .Concat(items.Skip(1).Take(items.Count() - 2).OrderBy(x => random.Next()))
            .Concat(items.Skip(items.Count() - 1))
            .ToList();
}

答案 2 :(得分:-1)

这不应该是一个大问题,您只需要创建一个临时列表,只包含您想要随机化的元素,然后将其合并回原始列表。

以下是一些概念性代码:

    // Randomize elements on a list
    // within range [firstElement, lastElement]
    void RandomizeList<T> ( List<T> list, int firstElement, int lastElement )
    {
        // Array with all elements to be randomized
        var randomized = new T[lastElement - firstElement];

        // Generate random indices
        // for randomized array
        var randomIds =new List<int> ( UniqueRandom (firstElement, lastElement-1) ).ToArray ();

        // Loop through all elements within the range
        // and fill list with items in a randomized order
        for (int i=firstElement; i!=lastElement; i++)
            randomized[i-firstElement] = list[randomIds[i - firstElement]];

        // Loop again to merge random elements into the list
        for (int i=firstElement; i!=lastElement; i++)
            list[i] = randomized[i-firstElement];
    }

    /// <summary>
    /// Returns all numbers, between min and max inclusive, once in a random sequence.
    /// Original code found in:
    /// https://stackoverflow.com/a/1011408/6033539
    /// </summary>
    IEnumerable<int> UniqueRandom( int minInclusive, int maxInclusive )
    {
        List<int> candidates = new List<int> ();
        for (int i = minInclusive;i <= maxInclusive;i++)
        {
            candidates.Add (i);
        }
        Random rnd = new Random ();
        while (candidates.Count > 0)
        {
            int index = rnd.Next (candidates.Count);
            yield return candidates[index];
            candidates.RemoveAt (index);
        }
    }