Как получить случайный объект с помощью Linq
Я пытаюсь получить случайный объект в linq. Вот как я это сделал.
//get all the answers
var Answers = q.Skip(1).Take(int.MaxValue);
//get the random number by the number of answers
int intRandomAnswer = r.Next(1, Answers.Count());
int count = 0;
//locate the answer
foreach(var Answer in Answers)
{
if (count == intRandomAnswer)
{
SelectedPost = Answer;
break;
}
count++;
}
Это лучший способ сделать это?
Ответы
Ответ 1
Как насчет:
SelectedPost = q.ElementAt(r.Next(1, Answers.Count()));
Дальнейшее чтение:
Комментарии ниже вносят хороший вклад в тесно связанные вопросы, и я включу их здесь, поскольку, как указывает @Rouby, люди, которые ищут ответ на них, могут найти этот ответ, и это будет неверно в этих случаях.
Случайный элемент во всем вводе
Чтобы сделать все элементы кандидатом в случайном выборе, вам нужно изменить ввод на r.Next
:
SelectedPost = Answers.ElementAt(r.Next(0, Answers.Count()));
@Zidad добавляет полезный метод расширения для получения случайного элемента по всем элементам последовательности:
public static T Random<T>(this IEnumerable<T> enumerable)
{
if (enumerable == null)
{
throw new ArgumentNullException(nameof(enumerable));
}
// note: creating a Random instance each call may not be correct for you,
// consider a thread-safe static instance
var r = new Random();
var list = enumerable as IList<T> ?? enumerable.ToList();
return list.Count == 0 ? default(T) : list[r.Next(0, list.Count)];
}
Ответ 2
Используйте Fisher-Yates-Durstenfeld shuffle.
(Вы можете использовать метод helper/extension для перетасовать последовательность IEnumerable<T>
. В качестве альтернативы, если вы использовали IList<T>
, вы могли бы если хотите, выполните обычную перетасовку.
Ответ 3
Еще один дурацкий подход (не самый эффективный для больших наборов данных):
SelectedPost = q.OrderBy(qu => Guid.NewGuid()).First();
Ответ 4
var rand = new Random();
var selectedPost = q.Skip(rand.Next(0, q.Count())).Take(1).FirstOrDefault();
Оптимально, вы хотите, чтобы когда-либо только выполнялся запрос функции для одного значения, поэтому вы устанавливаете Skip/Take, чтобы перейти к порядковому номеру, совпадающему со случайным числом, которое вы генерируете (ограничено набором данных itemcount, поэтому проблема с отсутствующей строкой ограничение на основе MAX (pkey) не является проблемой), а затем выхватывает первый элемент в этой точке последовательности.
В SQL это то же самое, что запрос SELECT Count(*) FROM q
, затем SELECT * FROM q LIMIT {0}, 1
где {0}
- это rand.Next(0, count)
, что должно быть довольно эффективным.
Ответ 5
Общий метод расширения, основанный на принятом ответе (который не всегда пропускает первый и перечисляет только однократно):
public static class EnumerableExtensions
{
public static T Random<T>(this IEnumerable<T> enumerable)
{
var r = new Random();
var list = enumerable as IList<T> ?? enumerable.ToList();
return list.ElementAt(r.Next(0, list.Count()));
}
}
Ответ 6
Поздно к вечеринке, но это высокий результат Google. Краткая версия может быть:
var rnd = new Random();
var SelectedPost = q.OrderBy(x => rnd.Next()).Take(1);
Недостаток заключается в том, что он применит случайное число ко всем элементам, но будет компактным и может быть легко изменен, чтобы принимать более одного случайного элемента.
Ответ 7
Я отправляю ответ, потому что у меня недостаточно репутации для комментариев.
Мне нравится этот ответ:
SelectedPost = q.ElementAt(r.Next(1, Answers.Count()));
Но ElementAt основано на нулевом значении, безусловно, начиная с 1 и переходя к Answers.Count(), вы собираетесь в конечном итоге потенциально выбросить диапазона, и вы никогда не получите первый объект.
Не будет ли
SelectedPost = q.ElementAt(r.Next(0, Answers.Count() - 1));
Лучше?
Ответ 8
Вытягивание всех ответов и их цикл не является самым эффективным способом, поскольку вы перемещаете множество данных из базы данных. Если вы используете целочисленный первичный ключ, который автоматически увеличивается, вы должны получить Max вашего первичного ключа, а затем найти случайное целое число в этом диапазоне. Затем сразу получите единственный ответ на основе первичного ключа, полученного из случайной функции.
Ответ 9
У меня есть таблица продуктов в базе данных, каждый раз, когда пользователь вводит одну деталь продукта, я хочу показать 10 похожих продуктов на странице ниже. И в каждом обновлении этот список должен быть изменен .it должен поступать случайным образом.
Linq выглядит так:
var products =
DataContextFactory.GetDataContext()
.Set<Product>()
.Where(x =>x.Id!=id)
.OrderBy(emp => Guid.NewGuid())
.Take(10).ToList();
x.Id!=id
это только для того, чтобы не отображать выбранный продукт.
Он отлично работает