Często potrzebujemy losowy element danej kolekcji. Aby nie pisać ciągle tego samego kodu wybierającego element losowy, możemy napisać metodę LINQ, którą użyjemy w dowolnym projekcie.
Metoda będzie się nazywać RandomElement.
Wymagania dla metody:
- przyjmuje źródło implementujące IEnumerable<T> i zwraca jeden element typu T
- przyjmuje opcjonalnie seed (kontrola nad generowanymi liczbami losowymi)
- jeżeli źródło jest nullem rzucany jest wyjątek ArgumentNullException
- jeżeli źródło nie zawiera elementów (kolekcja jest pusta) rzucany jest wyjątek InvalidOperationException
Implementacja:
Code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
public static class LinqExtensions
{
public static T RandomElement<T>(this IEnumerable<T> source, int? seed = null)
{
if (source == null)
{
throw new ArgumentNullException("source is null");
}
int count = 0;
if (source is ICollection<T>)
{
count = ((ICollection<T>)source).Count;
}
else
{
count = source.Count();
}
if (count == 0)
{
throw new InvalidOperationException("Source contains no elements");
}
Random random;
if (!seed.HasValue)
{
random = new Random();
}
else
{
random = new Random(seed.Value);
}
var list = source as IList<T>;
var index = random.Next(0, count);
if (list != null)
{
return list[index];
}
else
{
using(IEnumerator<T> e = source.GetEnumerator())
{
e.MoveNext();
while (index > 0)
{
e.MoveNext();
--index;
}
return e.Current;
}
}
}
}
}
Przedstawiona metoda została zoptymalizowana aby korzystać z możliwości które dają kolekcje. Jak wiadomo listy, tablice itd. można przeglądać odnosząc się do ich elementów poprzez indeks. Pobranie poprzez indeks wartości jest dużo szybsze niż iteracja po całej kolekcji i wybranie żądanej wartości.
Przykładowe użycie metody:
Code:
var sequence = Enumerable.Range(0, 100);
var selectec = sequence.RandomElement();
Brak komentarzy:
Prześlij komentarz