[英]What is the easiest way to get 4(or any count) random unique ids from an id collection with c#?
Assume that you have an idCollection IList<long>
and you have a method to get 4 unique ids.Every time you call it, it gives you random 4 unique ids ? 假设您有一个idCollection IList<long>
并且有一个获取4个唯一ID的方法,每次调用它都会给您随机提供4个唯一ID?
var idCollec = new[] {1,2,3,4,5,6,7,8,9,10,11,12}.ToList();
For example {2,6,11,12}
{3,4,7,8}
{5,8,10,12}
...
..
What is the smartest way to do it ? 最聪明的方法是什么?
Thanks 谢谢
Seems like easiest way would be to have something like: 似乎最简单的方法是:
if(idCollection.Count <4)
{
throw new ArgumentException("Source array not long enough");
}
List<long> FourUniqueIds = new List<long>(4);
while(FourUniqueIds.Count <4)
{
long temp = idCollection[random.Next(idCollection.Count)];
if(!FourUniqueIds.Contains(temp))
{
FourUniqueIds.add(temp);
}
}
It can be done with a nice LINQ query. 可以使用一个不错的LINQ查询来完成。 The key to doing it without the risk of getting duplicates, is to create a never ending IEnumerable of random integers. 做到无重复风险的关键是创建一个永无休止的IEnumerable随机整数。 Then you can take n distinct values from it, and use them as indexes into the list. 然后,您可以从中获取n个不同的值,并将它们用作列表的索引。
Sample program: 示例程序:
using System;
using System.Collections.Generic;
using System.Linq;
namespace TestRandom
{
class Program
{
static void Main(string[] args)
{
// Just to prepopulate a list.
var ids = (from n in Enumerable.Range(0, 100)
select (long)rand.Next(0, 1000)).ToList();
// Example usage of the GetRandomSet method.
foreach(long id in GetRandomSet(ids, 4))
Console.WriteLine(id);
}
// Get count random entries from the list.
public static IEnumerable<long> GetRandomSet(IList<long> ids, int count)
{
// Can't get more than there is in the list.
if ( count > ids.Count)
count = ids.Count;
return RandomIntegers(0, ids.Count)
.Distinct()
.Take(count)
.Select(index => ids[index]);
}
private static IEnumerable<int> RandomIntegers(int min, int max)
{
while (true)
yield return rand.Next(min, max);
}
private static readonly Random rand = new Random();
}
} }
If you use this approach, make sure you do not try to take more distinct values than there are available in the range passed to RandomIntegers. 如果使用这种方法,请确保不要尝试使用比传递给RandomIntegers的范围内可用的值更多的不同值。
What about shuffling the set then just taking the first four each time? 洗牌然后每次只拿前四个呢?
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> e)
{
var r = new Random();
return e.OrderBy(x => r.Next());
}
Then something like this? 那是这样的吗? It would probably be faster to use a for loop instead of Take and Except. 使用for循环代替Take和Except可能会更快。
var ordered = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 10};
var random = ordered.Shuffle();
while(random.Count() > 0)
{
var ourSet = random.Take(4).ToList();
random = random.Except(ourSet);
}
If the IList <long>
is populated with non unique values, you could use LINQ's Distinct() in combination with Take(), if it already has unique values, just use Take(). 如果IList <long>
填充有非唯一值,则可以将LINQ的Distinct()与Take()结合使用,如果它已经具有唯一值,则只需使用Take()。
List<long> myUniqueIds = //prepoulation
var first4UniqueUnused = myUniqueIds.Take(4);
var next4UniqueUnused = myUniqueIds.Where(l=>!first4UniqueUnused.Contains(l)).Take(4);
another way that is too easy, i think we've been making it too hard: 另一种太简单的方式,我认为我们一直在努力:
List<long> myIDs = //prepopulation;
List<long> my4Random = new List<long>();
Random r = new Random();
for(int i=0; i< 4; i++)
{
int j = r.Next();
while(j>myIDs.Count || my4Random.Contains(myIDs[j]))
j = r.Next();
my4Random.Add(myIDs[j]);
}
Random random = new Random();
long firstOne = idCollection[random.Next(idCollection.Count)];
long secondOne = idCollection[random.NExt(idCollection.Count)];
...and so on ...等等
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.