I am trying to get a random object within linq. Here is how I did.
//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++;
}
Is this the best way to do this?
What about:
SelectedPost = q.ElementAt(r.Next(1, Answers.Count()));
Further reading:
The comments below make good contributions to closely related questions, and I'll include them here, since as #Rouby points out, people searching for an answer to these may find this answer and it won't be correct in those cases.
Random Element Across Entire Input
To make all elements a candidate in the random selection, you need to change the input to r.Next:
SelectedPost = Answers.ElementAt(r.Next(0, Answers.Count()));
#Zidad adds a helpful extension method to get random element over all elements in the sequence:
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)];
}
Another wacky approach (not the most efficient for larger data sets):
SelectedPost = q.OrderBy(qu => Guid.NewGuid()).First();
Use a Fisher-Yates-Durstenfeld shuffle.
(You could use a helper/extension method to shuffle your IEnumerable<T> sequence. Alternatively, if you were using an IList<T> you could perform an in-place shuffle, if you prefer.)
Generic extension method based on the accepted answer (which doesn't always skip the first, and only enumerates the enumerable once):
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()));
}
}
Late to the party but this is a high-up Google result. A succinct version could be:
var rnd = new Random();
var SelectedPost = q.OrderBy(x => rnd.Next()).Take(1);
It has the disadvantage that it'll apply a random number to all elements, but is compact and could easily be modified to take more than one random element.
var rand = new Random();
var selectedPost = q.Skip(rand.Next(0, q.Count())).Take(1).FirstOrDefault();
Optimally, you want to only ever make the function query for a single value, so you set up the Skip/Take to jump up to the sequence number matching the random number you're generating (bounded by dataset's itemcount, so the missing row problem bounding based on MAX(pkey) isn't an issue) and then snag the first item at that point in the sequence.
In SQL this is the same as querying for SELECT Count(*) FROM q, then SELECT * FROM q LIMIT {0}, 1 where {0} is rand.Next(0, count), which should be pretty efficient.
Pulling all of the answers and looping them isn't the most efficient way as you're moving lots of data from the database. If you're using an integer primary key that's automatically incrementing, you should get the Max of your primary key and then find the random integer within that range. Then directly get the single answer based on the primary key derived from the random function.
I'm posting an answer because I don't have enough reputation to comment.
I like this answer:
SelectedPost = q.ElementAt(r.Next(1, Answers.Count()));
But ElementAt is zero based, surely starting at 1 and going to Answers.Count() you are going to end up potentially throwing an out of range, and you are never going to get the first entity.
Wouldn't
SelectedPost = q.ElementAt(r.Next(0, Answers.Count() - 1));
Be better?
I have product table in database ,every time user enters one product detail I want to show 10 similar products in below of page.And in every refresh this list must be change .it must come randomly.
Linq looks like this
var products =
DataContextFactory.GetDataContext()
.Set<Product>()
.Where(x =>x.Id!=id)
.OrderBy(emp => Guid.NewGuid())
.Take(10).ToList();
x.Id!=id
this only for not put selected product to list .
It works perfect
Related
var ids = new List<Guid>(count);
I have a multiple items empty list and I am looking for an elegant way to fill it with random Guids, without using for loop, preferably one-liner.
Inefficient but one line:
var list = Enumerable.Range(0, count).Select(_ => Guid.NewGuid()).ToList();
Much more efficient:
var list = new List<Guid>(count);
for (int i = 0 ; i < count ; i++) list.Add(Guid.NewGuid());
If the list already exists, then... just use the second version. You can probably force LINQ to do it without using a loop in your code, but: don't do that. You are looping here, so ... use a loop! Moving the loop into LINQ doesn't improve things - it just makes it harder to read and less efficient to execute.
Maybe this is more to your taste, even if its not exactly what you asked for?
static IEnumerable<Guid> RandomGuids()
{
while (true) { yield return Guid.NewGuid(); }
}
I currently have a dictionary with an int key and the value is an instance of a class called MachinePart.
The key is significant to the what type of machine part the MachinePart is. For example, if the key is between 0-99 the machine part is in a category called "Free Movement". If the key is between 100-199,the machine part is in another category and so on...
Therefore it is useful to have a method which will retrieve a certain category from the dictionary. To clarify to return a list of Machine Parts who keys are within a certain range.
Below is the code I currently have to retrieve the free movement parts. It works fine however I was wondering if there was a more improved way of writing this instead of having to have a loop which iterates 99 times.
public static List<MachinePart> getFreeMovementParts(Dictionary<int, MachinePart> iMachineParts)
{
List<MachinePart> temp = new List<MachinePart>();
for (int i = 0; i < 99; i++)
{
MachinePart t;
if (iMachineParts.TryGetValue(i, out t))
{
temp.Add(t);
}
}
return temp;
}
You could use Linq to select the values as follows:
var freeMovementParts = iMachineParts.Where(it => it.Key >= 0 && it.Key <= 99)
.Select(it => it.Value)
.ToList();
But as suggested in the comments, it's better to think of an alternative data structure for the implementation. Also it is worth noting that iterating over the keys will lead to poor performance if the dictionary contains large number of items and you will lose the perf benefits of using the dictionary.
If you'd like to Linq-ify your code you can do something like this:
public static List<MachinePart> getFreeMovementParts(Dictionary<int, MachinePart> iMachineParts)
{
return Enumerable.Range(0, 99)
.Select(i => { iMachineParts.TryGetValue(i, out var mp); return mp; })
.Where(mp => mp != null)
.ToList();
}
It does not solve problems mentioned in the comments, a different data structure might still be more appropriate, the above is mostly just for fun.
Performance of this approach vs performance of the "enumerate all keys" approach - it is similar to DB indexes, on a small data set it is often cheaper to do a full scan (enumerate all keys). But when you need only a small subset of items from a large dictionary - it will be cheaper to do the item lookups based on known range of keys.
var r = from part in iMachineParts
where part.Key >= 0 && part.Key <= 99
select part.Value;
return r.ToList();
I try to get random record from database:
personToCall = db.Persons.Skip(toSkip).Take(1).First();
but I get exception which tells me:
{"The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'."}
Can I do it without OrderBy? Sorting data structure (O(nlogn)) to pick random element(which should be constant) doesn't look wise.
EDIT: I use Entity Framework 6.1.1.
You can have something like :
personToCall = db.Persons.OrderBy(r => Guid.NewGuid()).Skip(toSkip).Take(1).First();
You should use FirstOrDefault to be mode defensive.
Here the dark lord teaching the force to yoda! what is the world coming to!
First you need to get the random number from 1 to max record, see this
Random rand = new Random();
int toSkip = rand.Next(0, db.Persons.Count());
db.Persons.Skip(toSkip).Take(1).First();
with order by you can use the Guid.NewGuid()
db.Persons.OrderBy(x=>x.Guid.NewGuid()).Skip(toSkip).Take(1).FirstOrDefault();
There is no way to do this without an ordering clause.
personToCall = db.Persons.OrderBy(r => Random.Next()).First();
That could be slow depending on the size of your Persons table, so if you wanted to make this fast, you'd have to add a column to Person, or join it to a dictionary of random numbers and Person keys, then order by that. But that is rarely a wise solution.
Better to ask a higher level question about the overall task at hand.
To avoid the OrderBy, dump to a List and random pick against the Index:
VB
With New List(Of Persons)
.AddRange(db.Persons)
PersonToCall = .Item(New Random().Next(0, .Count - 1))
End With
C#
var people = new List<Persons>();
people.AddRange(db.Persons);
personToCall = people.Item(new Random().Next(0, people.Count - 1));
I have three entity framework objects, Quiz, Question, and Option. A Quiz has a collection of Question objects, and a Question has a collection of Option objects. I would like to return from the DBContext a randomized list of questions for a specified quiz and each question should include a randomly sorted collection of associated Options.
So far, I have been able to get the random list of questions out successfully, but I am having trouble randomizing the options for the question.
Note: I have a couple of different shuffling extension methods I have written, in this example I am using ordering by a Guid for sake of simplicity.
var questions = db.Questions.Where(q => q.QuizId == quizId).Include(q => q.Options).OrderBy(a => Guid.NewGuid());
How can I randomly shuffle the Options?
I'm not sure LINQ-to-SQL will support conversion of such a specific feature. In your boots, if I had access to the database, I'd create a stored procedure like described here to fetch random rows on the database level. Though, this is also a not-optimal solution (see accepted answer to this question)
You may go for the following approach (assuming you have less than MAXINT questions):
Random random;
var c = Questions.Count();
var randomNumbers = new List<int>();
var fetchedQuestions = new List<Question>();
var randomNumber = random.Next(1,c);
for (int i = 0; i < maxQuestions; i++) {
while (randomNumbers.Contains(randomNumber))
randomNumber = random.Next(1,c);
randomNumbers.Add(randomNumber);
fetchedQuestions.Add(Questions.ElementAt(randomNumber));
}
return fetchedQuestions;
I.e. just generate some random unique question row numbers and fetch corresponding rows.
WARNING! Optimization needed before using - this is a dirty code prototype.
This question has been asked in one or the other way on SO but not like this. I just came over a very basic issue where I was looking for a statisfying solution :-)
I got a list of objects which have two integer properties. Now I want to find the max value of both properties of all object in the list.
I came up with three solutions:
First approach:
int max = Math.Max(list.Max(elem => elem.Nr), list.Max(elem => elem.OtherNr));
Second approach:
public int Max(List<Thing> list)
{
int maxNr = 0;
foreach (var elem in list)
{
if (elem.Nr > maxNr)
maxNr = elem.Nr;
if (elem.OtherNr > maxNr)
maxNr = elem.OtherNr;
}
return maxNr;
}
A third approach would be to do the sorting by both attribute and then just take the first entry and get the one or the other property.
I would like to find the fastest way to do this. So of all approaches I like the second one the post (from the performace point of view). Even though the first one is shorter you have to go through the list twice.
Any other solutions?
If you do
int max = list.Max(elem => Math.Max(elem.Nr, elem.OtherNr));
it's still a single-liner but only iterates through the list once. I'd take the single-linedness over the probable slight reduction in efficiency from writing it out by hand.
(Also, don't you need a cast from double to int somewhere in there?)
An alternative solution using LINQ if you need more than 2 properties (which is the limit of Math.Max):
int max = list
.SelectMany(elem => new[]{ elem.Prop1, elem.Prop2, elem.Prop3 })
.Max();