Random selection of query result Linq - c#

i have a query which will result 10 or 20 or any number number of rows. Below is the query.
var q = (from c in session.DB.Question where c.Level='1' && c.Group='1' select c);
This query can give me any number of rows.
But i have to show just 1 row from the result. I can select top 1/first but i would like select randomly.
i saw a topic about this: How to request a random row in SQL?
but i want it in LinQ
Please help me how to get random row from the result.

Sort items by random value and select first:
var q = (from c in session.DB.Question
where c.Level =='1' && c.Group =='1'
select c)
.OrderBy(o => SqlFunctions.Rand())
.First();

Thanks all. i found it and working:
var q = (from c in Session.DB.WinQuestionSet
where c.Level == "easy" && c.Grade == "1"
select c).OrderBy(x => Guid.NewGuid()).Take(1).Single();
label1.Text = q.Text;

I assume that your questions has an Id. Please see example below. I used Random class to generate random number.
List<Question> questions = new List<Question>
{
new Question { Id = 10, Name = "What?" },
new Question { Id = 12, Name = "How?" },
new Question { Id = 32, Name = "When?" },
new Question { Id = 41, Name = "Where?" },
};
var q = (from c in questions select c);
int i = 1;
Dictionary<int, int> questionKeys = new Dictionary<int, int>();
foreach (var item in questions)
{
questionKeys.Add(i, item.Id);
i++;
}
Random rdm = new Random();
int randomRow = rdm.Next(1, q.Count());
var questionId = questionKeys.Where(x => x.Key == randomRow).Select(x => x.Value).Single();
var result = q.Where(x => x.Id == questionId).Single();
Console.WriteLine(result.Name);

Assuming data is your data rows:
Random rand = new Random();
var row = data.ElementAt(rand.Next(data.Count));
Note that this does not work for Linq to SQL, and thus should be used after you query your db.

Related

Linq group by bahaving strangely

I have a simple list of int with three elements, all of them are set to 1000.
If I group this list by values, I still get three elements instead of just one.
Why?
var l = new List<int> {1000, 1000, 1000};
var gr = from i in l
group i by new
{
j = i
}
into g1
from g in g1
select new
{
Id = g1.Key.j
};
var count = gr.Count(); // <- count is 3!
Loose the second from
var l = new List<int> {1000, 1000, 1000};
var gr = from i in l
group i by new
{
j = i
}
into g1
select new
{
Id = g1.Key.j
};
var count = gr.Count(); // <- count is 1!
That's because you are again projecting the grouped items. It is returning IEnumerable<IGrouping<int,int>> and you are enumerating IEnumerable<int> with from g in g1 which means you will get the items which are in group 1000 and thus the count 3.
Following query will give you correct result:-
var gr = from i in l
group i by i
into g1
select new
{
Id = g1.Key
};
gr.Count() will be 1 here since we are projecting the Key and not the items inside that group.
With Method Syntax:
You currect query is : l.GroupBy(x => x).SelectMany(x => x) so it will project all the items in the group thus Count 3.
If you want to count the Key then: l.GroupBy(x => x).Select(x => x.Key) this will return 1 since it will create a single group of 1000.
I think you're trying to achieve this:
var l = new List<pairs>
{
new pairs {Index = 0, Value = 1000},
new pairs {Index = 1, Value = 1000},
new pairs {Index = 2, Value = 1000},
};
var gr = l.GroupBy(a => a.Value);
var count = gr.Count(); // <- count is 1
Where Pairs is a simple POCO:
internal class pairs
{
public int Value { get; set; }
public int Index { get; set; }
}
The group by clause gives you the key along with all of the items that are in the group. You are selecting the items and not the key.
For example, try this:
var gr = from i in l
group i by i into g1
select g1;
var count = gr.Count();
var itemCount = gr.First().Count();

Save list to to database

I have created a function on my restaurant review site that finds the cuisine of the last review and then finds other reviews of the same cuisines with a greater average score and then saves the restaurant id of those reviews into a table on the database. However I keep on getting the error:
Cannot assign method group to an implicitly-typed local variable.
on the line restaurantid = choices.Any help would be grateful.
var averagescore = db.Reviews
.Where(r => r.Cuisine == review.Cuisine)
.Average(r => r.score);
var choices = (from r in db.Reviews
where r.score <= averagescore
select r.RestaurantId).ToList;
foreach (var item in choices)
{
var suggestion = new Suggestion()
{
id = review.id,
Userid = review.UserId,
restaurantid = choices
};
db.Suggestions.Add(suggestion);
db.SaveChanges();
}
Following line:
var choices = (from ...).ToList;
Should be:
var choices = (from ...).ToList();
Secondly, it looks to me that restaurantid is of type int. With your code you're assigning a List<int> to the int. This should be item, from the loop.
You need to make the following change:
var averagescore = db.Reviews
.Where(r => r.Cuisine == review.Cuisine)
.Average(r => r.score);
var choices = (from r in db.Reviews
where r.score <= averagescore
select r.RestaurantId).ToList;
foreach (var item in choices)
{
var suggestion = new Suggestion()
{
id = review.id,
Userid = review.UserId,
restaurantid = item //here was your problem, you need to assign an id not a list of ids
};
db.Suggestions.Add(suggestion);
db.SaveChanges();
}
Have you tried like this:
var choices = (from r in db.Reviews
where r.score <= averagescore
select r).ToList;
foreach (var item in choices)
{
var suggestion = new Suggestion()
{
id = item.id,
Userid = item.UserId,
restaurantid = item.Restaurantid
};
db.Suggestions.Add(suggestion);
db.SaveChanges();
}

Select Single Element from Jagged Array

I'm working on a problem that's making my brain melt although I don't think it should be this hard. My example is long so I'll try to keep my question short!
I have an Array object that contains some elements that are also Arrays. For example:
customerAddresses = new customer_address[]
{
new // address #1
{
customer_id = 6676979,
customer_address_seq = 1,
customer_address_match_codes = new []
{
new
{
customer_address_seq = 1,
customer_id = 6676979,
customer_match_code_id = 5
}
}
},
new // address #2
{
customer_id = 6677070,
customer_address_seq = 1,
customer_address_match_codes = new []
{
new
{
customer_address_seq = 1,
customer_id = 6677070,
customer_match_code_id = 4
},
new
{
customer_address_seq = 1,
customer_id = 6677070,
customer_match_code_id = 5
},
new
{
customer_address_seq = 1,
customer_id = 6677070,
customer_match_code_id = 3
}
}
},
new // address #3
{
customer_id = 6677070,
customer_address_seq = 2,
customer_address_match_code = new []
{
new
{
customer_address_seq = 2,
customer_id = 6677070,
customer_match_code_id = 4
},
new
{
customer_address_seq = 2,
customer_id = 6677070,
customer_match_code_id = 5
}
}
}
};
As you can see, the Array contains a number of address records, with one record per combination of customer_id and customer_address_seq. What I'm trying to do is find the best matching customer_address according to the following rules:
There must be customer_match_code_id equal to 4 and there must be one equal to 5
If there is a customer_match_code_id equal to 3, then consider that customer_address a stronger match.
According to the above rules, the 2nd customer_address element is the "best match". However, the last bit of complexity in this problem is that there could be multiple "best matches". How I need to handle that situation is by taking the customer_address record with the minimum customer_id and minimum customer_address_seq.
I was thinking that using LINQ would be my best bet, but I'm not experienced enough with it, so I just keep spinning my wheels.
Had to make a change to your class so that you are actually assigning your one collection to something:
customer_address_match_codes = new customer_address_match_code[]
{
new
{
customer_address_seq = 1,
customer_id = 6676979,
customer_match_code_id = 5
}
}
And then here is the LINQ that I've tested and does what you specify:
var result = (from c in customerAddresses
let isMatch = c.customer_address_match_codes
.Where (cu => cu.customer_match_code_id == 4).Any () &&
c.customer_address_match_codes
.Where (cu => cu.customer_match_code_id == 5).Any ()
let betterMatch = isMatch && c.customer_address_match_codes
.Where (cu => cu.customer_match_code_id == 3).Any () ? 1 : 0
where isMatch == true
orderby betterMatch descending, c.customer_id, c.customer_address_seq
select c)
.FirstOrDefault ();
I've worked up an example using your data with anonymous types here: http://ideone.com/wyteM
Not tested and not the same names but this should get you going
customer cb = null;
customer[] cs = new customer[] {new customer()};
foreach (customer c in cs.OrderBy(x => x.id).ThenBy(y => y.seq))
{
if(c.addrs.Any(x => x.num == "5"))
{
if(c.addrs.Any(x => x.num == "3"))
{
if (cb == null) cb = c;
if (c.addrs.Any(x => x.num == "2"))
{
cb = c;
break;
}
}
}
}
This sounds like a job for LINQ
var bestMatch = (from address in DATA
where address.customer_address_match_code.Any(
x => x.customer_match_code_id == 4)
where address.customer_address_match_code.Any(
x => x.customer_match_code_id == 5)
select address).OrderBy(
x => x.customer_address_match_code.Where(
y => y.customer_match_code_id >= 3)
.OrderBy(y => y.customer_match_code_id)
.First()
.customer_match_code_id).FirstOrDefault();
My theory is this: Select addresses that have both a customer_match_code_id == 4 and a customer_match_code_id == 5. Then sort them by the the lowest customer_match_code_id they have that are at least 3, and then take the very first one. If there are a customer_match_code_id that equals 3 then that one is selected, if not, some else is selected. If nothing matches both 4 and 5 then null is returned.
Untested.
Seems quite straight forward in LINQ:
var query =
from ca in customerAddresses
where ca.customer_address_match_codes.Any(
mc => mc.customer_match_code_id == 4)
where ca.customer_address_match_codes.Any(
mc => mc.customer_match_code_id == 5)
orderby ca.customer_id
orderby ca.customer_address_seq
orderby ca.customer_address_match_codes.Any(
mc => mc.customer_match_code_id == 3) descending
select ca;
var result = query.Take(1);
How does that look?

How to combine 2 linq statments with groupby clause into 1

I was wondering if i can consolidate below 2 linq statments into 1 statment. I am sure it should be possible, but various attempts i am unable to manage.
var prevProvisionsBySubBook = (from provision in prevProvisions
group provision by provision.SubBook
into subBookGrouping
select
new
{
Key = subBookGrouping.Key,
Value = subBookGrouping.Sum(t => t.ProvisionUSD)
});
var currentProvisionsBySubBook
= (from provision in currentProvisions
group provision by provision.SubBook
into subBookGrouping
select new
{
Key = subBookGrouping.Key,
Value = subBookGrouping.Sum(t => t.ProvisionUSD)
});
var adjustmentChangeBySubBook
= (from current in currentProvisionsBySubBook
select new
{
Key = current.Key,
Value = current.Value
- (prevProvisionsBySubBook.Any() ? prevProvisionsBySubBook.Where(t => t.Key == current.Key).Single().Value : 0)
});
any help would be apprecaited.
You can do it like this:
var adjustmentChangeBySubBook =
from provision in
(from currentProvision in currentProvisions select new
{
currentProvision.SubBook,
CurrentUSD = currentProvision.ProvisionUSD,
PreviousUSD = 0
}).Concat
(from prevProvision in prevProvisions select new
{
prevProvision.SubBook,
CurrentUSD = 0,
PreviousUSD = prevProvision.ProvisionUSD
})
group provision by provision.SubBook into subBookGrouping select new
{
subBookGrouping.Key,
Value = subBookGrouping.Sum(t => t.CurrentUSD - t.PreviousUSD)
};

Find the most frequent numbers in an array using LINQ [duplicate]

This question already has answers here:
Find the most occurring number in a List<int>
(6 answers)
Closed 9 years ago.
List<int> a = new List<int>{ 1,1,2,2,3,4,5 };
What's the quickest way to do this with LINQ?
I'm new to LINQ
The key here is using Enumerable.GroupBy and the aggregation method Enumerable.Count:
List<int> list = new List<int>() { 1,1,2,2,3,4,5 };
// group by value and count frequency
var query = from i in list
group i by i into g
select new {g.Key, Count = g.Count()};
// compute the maximum frequency
int whatsTheFrequencyKenneth = query.Max(g => g.Count);
// find the values with that frequency
IEnumerable<int> modes = query
.Where(g => g.Count == whatsTheFrequencyKenneth)
.Select(g => g.Key);
// dump to console
foreach(var mode in modes) {
Console.WriteLine(mode);
}
Jason's answer is correct, but you can perform this operation in one LINQ operation.
List<int> list = new List<int>() { 1, 1, 2, 2, 3, 4, 5 };
// return most frequently occurring items
var query = from i in list
group i by i into g
let maxFreq = (from i2 in list
group i2 by i2 into g2
orderby g2.Count() descending
select g2.Count()).First()
let gCount = g.Count()
where gCount == maxFreq
select g.Key;
// dump to console
foreach (var mode in query)
{
Console.WriteLine(mode);
}
public static Tres MostCommon<Tsrc, Tres>(this IEnumerable<Tsrc> source, Func<Tsrc, Tres> transform)
{
return source.GroupBy(s => transform(s)).OrderByDescending(g => g.Count()).First().Key;
}
And in your example with integral types you can call it as:
List<int> a = new List<int>{ 1,1,2,2,3,4,5 };
int mostCommon = a.MostCommon(x => x);
from num in a
group num by num into numg
let c = numg.Count()
order by c descending
select new { Number = numg.Key, Count = c }
I think the most frequent number can also be achieved in a single query like this-
var query = (from i in list
group i by i into g
orderby g.Count() descending
select new { Key = g.Key, Count = g.Count() }).FirstOrDefault();
if (query == null) Console.WriteLine("query = NULL");
else Console.WriteLine("The number '{0}' occurs {1} times.", query.Key, query.Count);
Null check is not really required but it may be useful when null is actually expected (like Empty list?)

Categories