LINQ How to Average an internal list - linq

What is the LINQ syntax for the Average need below. Both Select and SelectMany fail me.
I can Max() and Sum() my internal list, but Average() wont compile.
The JSON version of the simple list looks like
[{"Week":6, "Matches":[{"Game":189},{"Game":149},{"Game":132}]} ....
var hiGame = games.Max(g => g.Matches.Max(m => m.Game)); // ok
var hiSeries = games.Max(g => g.Matches.Sum(m => m.Game)); // ok
var ave = games.Average(g => g.Matches.SelectMany(m => m.Game)); // no go
The type arguments for method 'System.Linq.Enumerable.SelectMany(System.Collections.Generic.IEnumerable, System.Func>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I think you want your SelectMany on the outside:
var ave = games.SelectMany(g => g.Matches) // Flatten to a sequence of matches
.Average(m => m.Game); // Average by value of Game

Related

how to get the linq list having Ids from IEnumerable<Object>

The code below userModel.Carriers is the type of IEnumerable<CarrierModel>.
userModel.Carriers has a list of carriers having Ids. With those Ids, I want to get CarrierDivision usign linq. But, I can't get it right because linq sqlexpression is not compatible with IEnumerable expression.
userModel.Carriers = carriersForRegion.Select(carrier => Mapper.Map<CarrierModel>(carrier))
.ToList();
var carrierDivision = from c in db.CarrierDivision where c.Contains();
collection.Contains will generate .. WHERE CarrierId IN (1, 2, 3) sql query
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToArray();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
In case db.CarrierDivision returns IEnumerable(not database), then I would suggest to create HashSet of carrier ids.
var carrierIds = userModel.Carriers.Select(carrier => carrier.Id).ToHashSet();
var divisions = db.CarrierDivision
.Where(division => carrierIds.Contains(division.CarrierId))
.ToArray();
With HashSet search executed without extra enumerations - O(1)

Conditionally adding .Take()

Currently I have this that automatically takes 500 rows:
var orderQuery = subsetTable.Where(pred).OrderByDescending(o => o.CreationDate).Take(500);
I'd like to make the Take() conditional, something like this:
var orderQuery = subsetTable.Where(pred).OrderByDescending(o => o.CreationDate);
if (condition)
orderQuery = orderQuery.Take(500);
Is this possible?
Edit:
The compiler says
"Cannot implicitly convert type 'System.Linq.IQueryable' to
'System.Linq.IOrderedQueryable'."
Add "AsQueryable" to make the types line up:
var orderQuery = subsetTable.Where(pred).OrderByDescending(o => o.CreationDate).AsQueryable();
if (condition)
orderQuery = orderQuery.Take(500);
In Linq-to-Objects, the var will infer to IOrderedEnumerable<T>, where T is the type of your object. The Take() will yield an IEnumerable<T>, so your line of code there will not be allowed. (IOrderedEnumerable is more specified than IEnumerable, you need your query to typed in a less-specified manner.) And, as the comments point out, the same holds true for providers that deal in terms of IQueryable<T>, which itself can be expressed as a less specified IEnumerable<T>.
To make it work, explicitly type your query to the lesser specified type you need, IEnumerable<T> or IQueryable<T>, and then you can apply your conditional Take.
IEnumerable<YourType> orderedQuery = ...
if (condition)
orderedQuery = orderedQuery.Take(n);
Is this possible?
Yes. Your code should work nearly as written. You just have to eliminate the var. Assuming your type is Order. you'd use:
IQueryable<Order> orderQuery = subsetTable.Where(pred).OrderByDescending(o => o.CreationDate);
if (condition)
orderQuery = orderQuery.Take(500);
What I do is to add Sorting at the end, to avoid having to convert them
var orderQuery = subsetTable.Where(pred);
if (condition)
orderQuery = orderQuery.Take(500);
orderQuery = orderQuery.OrderByDescending(o => o.CreationDate);

Linq - Retrieve first list after SelectMany

I've an object list where each object contains an internal object list and what I would fetching is the father list (left list), however I'm forced to use SelectMany function..Is it possibile?
Naive Example:
var query = objList.SelectMany(p => p.InternalList)
.Where(internalObj => internalObj.SomeProprerty == true)
.SELECT(objList);
Is there any way to accomplish this?
Assuming you don't actually want objList, but instead the element of objList which we're looking at at the time, I think you just want:
var query = objList.SelectMany(p => p.InternalList, (o, p) => new { o, p })
.Where(pair => pair.p.SomeProperty)
.Select(pair => pair.o);
If that's not what you're after, it would really help if you'd give a concrete example.
EDIT: If you only want any example from objList where any element of the internal list has a SomeProperty value of true, you can do that more easily like this:
var value = objList.FirstOrDefault(o => o.InternalList.Any(p => p.SomeProperty));
if (value != null)
{
...
}

LINQ read Select values

I have a LINQ query where I want to select and read the p.Api value.
var api = DataAccessNew.Instance.dcServers.Where(p => p.Ip == IpAddress).Select(p => p.Api);
How do I read the p.Api value?
I have tried api.ToString() but I get SQL instead of actual column value.
You are getting an IEnumerable<> back (and your ToString call is showing you the value of that expression).
If you are expecting a single value, do this:
var api = DataAccessNew.Instance.dcServers
.Where(p => p.Ip == IpAddress)
.Select(p => p.Api)
.Single();
You might be interested to read about the other methods like Single(): SingleOrDefault, First, FirstOrDefault. Which one you used depends on whether you are expecting a single or multiple values returned (Single vs. First) and what you want to happen if there are no values (the *Default methods will return the type default instead of throwing an exception).
Or if you want to look at all the returned values:
var api = DataAccessNew.Instance.dcServers
.Where(p => p.Ip == IpAddress)
.Select(p => p.Api);
foreach (var apiValue in api)
{
// apiValue will have the value you're looking for.
}
Try this snippet of code:
string apiValue = api.FirstOrDefault().ToString();
your syntex seems ok..
By the way try this
string api =DataAccessNew.Instance.dcServers.Where(p => p.Ip == IpAddress).Select(p => p.Api).FirstOrDefault();
if p.Ip is a unique key in your table you could try to add .FirstOrDefault() after your Linq query.
public string getselectedvalue(ListBox l)
{
string vtext="",vval="";
var selectedQueryText = l.Items.Cast<ListItem>().Where(item => item.Selected);
var selectedQueryVal = l.Items.Cast<ListItem>().Where(item => item.Selected).Select(item => item.Value);
vtext= String.Join("','", selectedQueryText ).TrimEnd();
vval= String.Join("','", selectedQueryVal ).TrimEnd();
return v;
}

Linq ToDictionary Not Defined?

I have this code
var contacts = dr.mktDoctorContacts
.GroupBy(x => x.ContactType)
.Select(zb => new
{
Key = zb.Key,
GroupWiseContacts = zb.Select(x => x.Contact).ToList()
})
.ToDictionary<string,List<string>>(y => y.Key, y => y.GroupWiseContacts)
I don't know what is wrong with this code.
Compile time error msg says:System.Generic.IEnumerable does not contain definition of and best extension method overloads has some invalid arguments. i can see only two overloads of ToDictionary Method in my visual studio tooltip sort of documentation whereas i have come across more than two overloads of ToDictionary on the web
Edit Here is exact Error message at compile time
Error 13 'System.Collections.Generic.IEnumerable<AnonymousType#1>'
does not contain a definition for
'ToDictionary' and the best extension
method overload
'System.Linq.Enumerable.ToDictionary<TSource,TKey>(System.Collections.Generic.IEnumerable<TSource>,
System.Func<TSource,TKey>,
System.Collections.Generic.IEqualityComparer<TKey>)'
has some invalid arguments
The compiler message makes the error clear: There is no method ToDictionary which can accept the arguments and types specified.
The mistake here is in specifying the type arguments on ToDictionary. The MSDN documentation defines the extension method as ToDictionary<TKey, TSource>. The source in your example is IEnumerable<AnonymousType#1>, but you have specified a type of List<string>.
To correct the error, omit the type arguments; the compiler will infer the correct types. You can additionally combine the Select and ToDictionary transformations into a single statement:
var contacts = dr.mktDoctorContacts
.GroupBy(x => x.ContactType)
.ToDictionary(
y => y.Key,
y => y.Select(x => x.Contact).ToList());
Rewrote your code (and added .AsEnumerable()):
var dictionary = dr.mktDoctorContacts
.GroupBy(x => x.ContactType)
.AsEnumerable()
.ToDictionary(
i => i.Key,
i => i.Select(x => x.Contact).ToList()
)
);
Don't run that group operation in the database, it'll cause the elements of each group to be fetched in separate roundtrips.
ILookup<string, string> contacts = dr.mktDoctorContacts
.ToLookup<Contact, string, string>(x => x.ContactType, x => x.Contact);

Resources