Here is what I currently have:
from s in domainThreads.Values
where (s.IsAvailable)
select s;
but I'm still learning Linq and believe that I can get it all on one line. Does the following look correct?
domainThreads.Values.Where(s => s.IsAvailable).Any();
Do I need the .Any()?
Any() returns a boolean indicating whether or not there are any entities in the given set.
The equivalent of your original LINQ expression would simply be:
domainThreads.Values.Where(s => s.IsAvailable)
The two are not equivalent.
The first returns all Values where s.IsAvailable.
The second returns whether there are any such values.
A correct conversion is:
domainThreads.Values.Where(s => s.IsAvailable)
Which translates to:
domainThreads.Values.Where(s => s.IsAvailable).Select(s => s)
Which is what the original query gets transformed to anyways.
You don't need the Any() -- that will return a bool indicating if any of elements satisfy the condition.
Instead, just do:
domainThreads.Values.Where(s => s.IsAvailable)
domainThreads.Values.Where(s => s.IsAvailable)
is enough.
Any() returns a bool value, but your original query returns a data set. So just use Where()
var result = domainThreads.Values.Where(s => s.IsAvailable);
Any() would be helpful when you just need ensure that at least single item satisfies a condition
Try this
var obj = domainThreads.Values.Where(s => s.IsAvailable == true).Select(o => o);
If you call Any() it returns bool which indicates that you have at least one item.
domainThreads.Values.Where(s => s.IsAvailable);
this expression is enough and it is equivalent to the LINQ statement.
Any() returns a boolean that is true if the result contains one or more items.
var elements = from s in domainThreads.Values
where (s.IsAvailable)
select s;
//elements now contains a list of objects.
This is equivalent to:
elements = domainThreads.Where(s => s.IsAvailable);
It looks but is not the same. The result is boolean and returns true if the collection contains any elements.
You could write something like this, but is it really worth the effort?
var result = domainThreads.Values.Where(s => s.IsAvailable).Select(s => s);
or shorter:
var result = domainThreads.Values.Where(s => s.IsAvailable);
EDIT: if you just want to have one line of code you can also write:
from s in domainThreads.Values where s.IsAvailable select s;
It's much more readable and generates to the same code in the end.
Related
I have the following two LINQ statements which set different values in the same item in a list
List<MyClass> myList = GetList();
myList.Where(x => x.Name == "someName").Select(x => x.MyArray = someList.ToArray()).ToList();
myList.Where(x => x.Name == "someName").Select( x => x.AnotherValue = GetValue()).ToList();
Is it possible to combine this so both are set in the one expression?
myList
.Where(x => x.Name == "someName")
.ToList()
.ForEach(x => {
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
});
Why are you calling ToList() at the end of each of those expressions and discarding the result?
Also, Jon Skeet is right that this is an abuse of LINQ, and especially so in your original form: It's explicit that LINQ expressions aren't even necessarily expected to be fully enumerated. The fact that you needed those ToList() calls to make anything happen should have given you a grave and queasy sense that you were misusing a language feature. When you have to do something weird to use your chosen construct instead of the usual way of doing it, finish getting it to work (because weird is cool), and then go back and redo it the boring, lame way before you check it in.
What advantage do you see in the LINQ + ForEach() version above, compared to this version?
foreach (var x in myList.Where(x => x.Name == "someName"))
{
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
}
The old-style loop version is shorter, instantly understandable because it's the default idiom, and IMO cleaner. You don't have to do everything with LINQ.
N.B., ForEach() isn't LINQ; it's a member of List<T>. That's why you have to call ToList() to use it.
Just use the lambda operator to pass an entire lambda expression defined inside a
{...} block:
myList.Where(x => x.Name == "someName").Select(x => { x.MyArray = someList.ToArray(); x.AnotherValue = GetValue(); return x;}).ToList();
Suppose I do something like
var Ordered = MyList.OrderBy(x => x.prop1).ThenBy(x => x.prop2);
Does MyList.OrderBy(x => x.prop1) return the filtered list, and then does it further filter that list by ThenBy(x => x.prop2)? In other words, is it equivalent to
var OrderedByProp1 = MyList.OrderBy(x => x.prop1);
var Ordered = OrderedByProp1.OrderBy(x => x.prop2);
???
Because obviously it's possible to optimize this by running a sorting algorithm with a comparator:
var Ordered = MyList.Sort( (x,y) => x.prop1 != y.prop1 ? x.prop1 < y.prop1 : ( x.prop2 < y.prop2 ) );
If it does do some sort of optimization and intermediate lists are not returned in the process, then how does it know how to do that? How do you write a class that optimizes chains of methods on itself? Makes no sense.
Does MyList.OrderBy(x => x.prop1) return the filtered list
No. LINQ methods (at least typically) return queries, not the results of executing those queries.
OrderBy just returns an object which, when you ask it for an item, will return the first item in the collection given a particular ordering. But until you actually ask it for a result it's not doing anything.
Note you can also get a decent idea as to what's going on by just looking at what OrderBy returns. It returns IOrderedEnumerable<T>. That interface has a method CreateOrderedEnumerable which:
Performs a subsequent ordering on the elements of an IOrderedEnumerable according to a key.
That method is what ThenBy uses to indicate that there is a subsequent ordering.
This means that you're building up all of the comparers that you want to be used, from the OrderBy and all ThenBy calls before you ever need to generate a single item in the result set.
For more specifics on exactly how you can go about creating this behavior, see Jon Skeet's blog series on the subject.
I need do a filter that request data with a parameter included in a list.
if (filter.Sc.Count > 0)
socios.Where(s => filter.Sc.Contains(s.ScID));
I try on this way but this not work, I tried also...
socios.Where( s => filter.Sc.All(f => f == s.ScID));
How I can do a filter like this?
socios.Where(s => filter.Sc.Contains(s.ScID));
returns a filtered query. It does not modify the query. You are ignoring the returned value. You need something like:
socios = socios.Where(s => filter.Sc.Contains(s.ScID));
but depending on the type of socios the exact syntax may be different.
In addition to needing to use the return value of your LINQ .Where(), you have a potential logic error in your second statement. The equivalent logic for a .Contains() is checking if Any of the elements pass the match criteria. In your case, the second statement would be
var filteredSocios = socios.Where( s => filter.Sc.Any(f => f == s.ScID));
Of course if you can compare object-to-object directly, the .Contains() is still adequate as long as you remember to use the return value.
I know this is simple, but my mind is playing tricks on me right now. If we have a flat list of objects with the properties GroupSortIndex and ItemSortIndex (within the group) and we want to find the first item in the list, what's the Linq/lambda for that?
About all I can think of is (meta, not literal code...)
var soughtItem = Source.OrderBy(ItemSortIndex).OrderBy(GroupSortIndex).ToList()[0]
...but that just looks so wrong to me for some reason.
Read post : Default Extension methods to get difference between first and firstordefault
you can use FirstOrDefualt() or First() function
var soughtItem = Source.OrderBy(ItemSortIndex).
ThenBy(GroupSortIndex).FirstOrDefualt();
if(soughtItem !=null)//advantage of using firstordefault
{
}
its better to use FirstOrDefualt because if there is no data it will return null intead of excetipn
You can use IOrderedEnumerable.ThenBy (Note: an IOrderedEnumerable is returned from IEnumerable.OrderBy):
var firstItem = source.OrderBy(s => s.GroupSortIndex)
.ThenBy(s => s.ItemSortIndex)
.First();
This orders first by the group and then by the item. You should use FirstOrDefault if the sequence can be empty. Otherwise First raises an exception.
(i've assumed that you want to order first by group and then by the item instead, since the ItemSortIndex is the index of the item within the group(as mentioned))
var soughtItem = Source
.OrderBy(ItemSortIndex)
.ThenBy(GroupSortIndex).First();
If ItemSortIndex and GroupSortIndex are properties instead of functions, then you need:
var soughtItem = Source
.OrderBy(i => ItemSortIndex)
.ThenBy(i => GroupSortIndex).First();
Is there a way I can do something like this with Lambda expressions?
responses.Add(sr).Where(v.Responses.TryGetValue(v.responseType, out sr));
I want to use lambda expressions or a ternary operator instead of a typical if expression.
NB:
responses is a List<string> type.
v.Responses is a Dictionary of <enum ResponseType, string>
v is some object
sr is a string.
What you want to do is:
string sr;
if (v.Responses.TryGetValue(v.responseType, out sr))
responses.Add(sr);
There is no way to ease the syntax and get the same performance.
But you could do:
responses.AddRange( v.Responses.Where( p => p.Key == v.responseType )
.Select( p => p.Value ) );
You may want to think about what the last one is doing, because it is kind of stupid...
EDIT: the reason why it is stupid is because the last expression translates into:
foreach(var pair in v.Responses)
{
if (pair.Key == v.responseType)
responses.Add(pair.Value);
}
So if your ResponseType enumeration had 6 million entries, the program would iterate over the entire set of keys to find the correct entry. In your case, since you already know the key, you should use v.Responses[key] as it is extremely fast (see in which cases dictionaries must be use).
LINQ is not supposed to modify collections.
Couldn't you simply do something like this:
string sr;
if(v.Responses.TryGetValue(v.responseType, out sr))
responses.Add(sr);
If I understand your question correctly, this might do what you're looking for.
Based on your example code, I'm assuming that your object "v" contains a field named "responseType" of type RepsonseType.
var responses = v.Responses
.Where(r => r.Key == v.responseType)
.Select(r => r.Value)
.ToList();