c#从列表中均匀选择N个元素而不进行随机播放

时间:2017-09-13 11:57:02

标签: c# algorithm list

我想从N个元素的列表中统一选择K个元素,而不需要对列表进行混洗。所以算法应该总是产生相同的结果。

E.g。

int N = 100;

List<int> myList = Enumerable.Range(0, N-1).ToList();

int K = 20;
  

我希望结果如下:0, 5, 10, 15, 20, ...

     

E.g。 if K == 50我希望:0, 2, 4, 6, 8, ...

但是我不知道如何解决它,例如K = 53?我仍然想从列表中获取统一的元素,但在这种情况下,我们不能简单地从列表中获取每个第二个元素。简单的方法是对元素进行混洗并从列表中取出第一个K元素,再次对列表进行排序,但在这种情况下,算法的结果每次都会产生不同的结果,每次都需要相同的结果。

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:4)

如果它们都是等距的,则查找索引是什么,并舍入到最接近的整数。

int N = 100;

List<int> myList = Enumerable.Range(0, N).ToList();

double K = 53;

List<int> solutions=new List<int>();
for (int i=1;i<=K;i++)
{
    solutions.Add(myList[(int)Math.Round(i*(N/K)-1)]);
}

Console.WriteLine(solutions.Count);
Console.WriteLine(string.Join(", ", solutions));

查看示例:DEMO

编辑:Math.Floor的效果优于Math.Round,因为Math.Round为N = 5,K = 3提供了错误的解决方案:

Math.Round->1,2,4
Math.Floor->0,2,4 

查看示例:DEMO2

答案 1 :(得分:0)

此问题与线条绘制算法完全相同:https://en.wikipedia.org/wiki/Line_drawing_algorithm

在您的情况下,您想要从(0,0)到(20,52)

画一条线

答案 2 :(得分:-1)

你仍然可以随机播放列表。请参阅以下示例

var n = 100;
var k = 53;

var originalList = GetListWithNElements(n);
var shuffledList = ShuffleList(originalList);
var firstKElements = GetFirstKElements(k, shuffledList);

[...]

List<int> GetListWithNElements(int n)
{
  return Enumerable.Range(0, n-1).ToList();
}

List<int> ShuffleList(List<int> originalList)
{
  List<int> copy = originalList.ToList();
  List<int> result = new List<int>();
  Random randomGenerator = new Random(314159); 

  while(copy.Any())
  {
    int currentIndex = randomGenerator.Next(copy.Count);
    result.Add(copy[currentIndex]);
    copy.RemoveAt(currentIndex);
  }

  return result;
}

List<int> GetFirstKElements(int k, List<int> shuffledList)
{
  return shuffledList.Take(k).ToList();
}

Random使用常量种子进行初始化,因此每次都会产生相同的“random”值序列,因此每次都会使用相同的元素。

答案 3 :(得分:-2)

请尝试以下操作:

        static void Main(string[] args)
        {
            const int N = 100;
            {
                List<int> myList = Enumerable.Range(0, N - 1).ToList();
                int seed = 5;
                int numberOfItems = 50;
                List<int> results = TakeNItems(myList, seed, numberOfItems);
            }
        }
        static List<int> TakeNItems(List<int> data, int seed, int numberOfItems)
        {
            Random rand = new Random(seed);

            return data.Select((x,i) =>  new { x = x, index = i, rand = rand.Next()})
                .OrderBy(x => x.rand)
                .Take(numberOfItems)
                .OrderBy(x => x.index)
                .Select(x => x.x)
                .ToList();
        }