I use C# Asp.net 4 and Linq.
I have a Generics of type BOOL.
I need to check if at least an element in the Generics is TRUE.
At the moment I'm using the Contains method (all is working fine).
List<bool> userIsValid = new List<bool>();
userIsValid.Add(false);
userIsValid.Add(true);
userIsValid.Add(false);
if (userIsValid.Contains(true))
// do smt here
I would like to know if exist another approach without using the Contains method.
Many Thanks!
You can use Any():
if(userIsValid.Any(b => b)) { ... }
This will return true as soon as it hits a true condition specified by the lambda. In this case as the values in your list are booleans it simply needs to check the value. A more verbose way of writing it would be .Any(b => b == true) but this is unnecessary.
You could do this:
if (userIsValid.Aggregate((x,y) => x || y)) { ... }
I wouldn't do this because it is not very clear code, and it is actually slower than the other options because it won't return as soon as it finds a true.
But if you are just looking for esoteric solutions...
These would work:
Exists()
userIsValid.Exists(true);
or
Any()
userIsValid.Any(x => x);
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();
Asume we have a list of objects (to make it more clear no properties etc.pp are used)
public class SomeObject{
public bool IsValid;
public int Height;
}
List<SomeObject> objects = new List<SomeObject>();
Now I want only the value from a list, which is both valid and has the lowest height.
Classically i would have used sth like:
SomeObject temp;
foreach(SomeObject so in objects)
{
if(so.IsValid)
{
if (null == temp)
temp = so;
else if (temp.Height > so.Height)
temp = so;
}
}
return temp;
I was thinking that it can be done more clearly with LinQ.
The first approach which came to my mind was:
List<SomeObject> sos = objects.Where(obj => obj.IsValid);
if(sos.Count>0)
{
return sos.OrderBy(obj => obj.Height).FirstOrDefault();
}
But then i waas thinking: In the foreach approach i am going one time through the list. With Linq i would go one time through the list for filtering, and one time for ordering even i do not need to complete order the list.
Would something like
return objects.OrderBy(obj => obj.Height).FirstOrDefault(o => o.IsValid);
also go twice throught the list?
Can this be somehow optimized, so that the linw also only needs to run once through the list?
You can use GroupBy:
IEnumerable<SomeObject> validHighestHeights = objects
.Where(o => o.IsValid)
.GroupBy(o => o.Height)
.OrderByDescending(g => g.Key)
.First();
This group contains all valid objects with the highest height.
The most efficient way to do this with Linq is as follows:
var result = objects.Aggregate(
default(SomeObject),
(acc, current) =>
!current.IsValid ? acc :
acc == null ? current :
current.Height < acc.Height ? current :
acc);
This will loop over the collection only once.
However, you said "I was thinking that it can be done more clearly with LinQ." Whether this is more clear or not, I leave that up to you to decide.
You can try this one:
return (from _Object in Objects Where _Object.isValid OrderBy _Object.Height).FirstOrDefault();
or
return _Objects.Where(_Object => _Object.isValid).OrderBy(_Object => _Object.Height).FirstOrDefault();
Would something like
return objects.OrderBy(obj => obj.Height).FirstOrDefault(o => o.IsValid);
also go twice throught the list?
Only in the worst case scenario, where the first valid object is the last in order of obj.Height (or there is none to be found). Iterating the collection using FirstOrDefault will stop as soon as a valid element is found.
Can this be somehow optimized, so that the linw also only needs to run
once through the list?
I'm afraid you'd have to make your own extension method. Considering what I've written above though, I'd consider it pretty optimized as it is.
**UPDATE**
Actually, the following would be a bit faster, as we'd avoid sorting invalid items:
return object.Where(o => o.IsValid).OrderBy(o => o.Height).FirstOrDefault();
Based on a proposed answer to my other question here... is it possible to update a variable during LINQ enumeration so you can use it as part of a test?
For instance, is anything like this possible?
// Assume limitItem is of type Foo and sourceList is of type List<Foo>
// Note the faux attempt to set limitItemFound in the TakeWhile clause
// That is what I'm wondering.
sourceList.Reverse()
.TakeWhile(o => (o != limitItem) && !limitItemFound; limitItemFound = limitItemFound || (o == limitItem) )
.FirstOrDefault(o => ...);
This would make the search inclusive of limitItem.
For LINQ to Objects (which takes delegates) then you can, yes - using a statement lambda:
sourceList.Reverse()
.TakeWhile(o => {
... fairly arbitrary code here
return someValue;
})
.FirstOrDefault(o => ...);
I would strongly discourage you from doing this though. It will make it much harder to understand what's going on, because you're losing the declarative nature of idiomatic LINQ code.
I have an interface method whose signature is as follows:
void SetValues(IDictionary<string, object> the_values);
I have a client class that uses that method. I want The unit test for that class to verify that, in a particular case, a specific key and value pair are passed in. Right now, if I want to express that I'm expecting the SetValues method to be called with the single key-value pair { "Date", DateTime(1972,1,2) } I write the following:
item.Expect(i => i.SetValues(
Arg<IDictionary<string, object>>.Matches(
(items) => (items.Count() == 1 &&
items.First().Key == "Date" &&
(DateTime) items.First().Value == new DateTime(1972,1,2))));
The expectation seems to work, but my does that look ugly. Is there a better way to express expectations about the contents of a collection being passed in as a parameter?
Most likely no. I agree this is border line ugly. But what's even more important, it produces undecipherable exception message, like this:
IInterface.SetValues(items => items.Count() == 1 &&
items.First().Key == "Date" &&
(DateTime) items.First().Value == new DateTime(1972,1,2)); Expected #1, Actual #0.
Yeah, you'll know it failed. Not very useful information in 2 weeks time. Truth to be told, when this happens you'll most likely have to debug it to get to know what's going on. Instead, I suggest doing this:
item.Expect(i => i.SetValues(Arg<IDictionary<string, object>>.Is.Anything))
.WhenCalled(invocation =>
{
var items = invocation.Arguments
.OfType<IDictionary<string, object>>()
.First();
Assert.That(items.Count(), Is.EqualTo(1));
Assert.That(items.First().Key, Is.EqualTo("Date");
// ...
});
Or, putting verification into it's own method altogether:
item.Expect(i => i.SetValues(IsCalledWithCorrectPair()));
// ...
private IDictionary<string, object> IsCalledWithCorrectPair()
{
return Arg<IDictionary<string, object>>.Matches(items =>
{
Assert.That(items.Count(), Is.EqualTo(1));
Assert.That(items.First().Key, Is.EqualTo("Date");
// ...
return true;
});
}
For small fixed number of expecte item in a dictionary I think simple check for Count and particular entries is expressive enough. Test will fail if values are wrong...
items.Count() == 1 && items["Date"]== new DateTime(1972,1,2);
You can also use collection comparisons as covered in Comparing two collections for equality irrespective of the order of items in them.
Here's the c# code that I have:
private double get806Fees (Loan loan)
{
Loan.Fee.Items class806;
foreach (Loan.Fee.Item currentFee in loan.Item.Fees)
{
if (currentFee.Classification == 806) class806.Add(currentFee);
}
// then down here I will return the sum of all items in class806
}
Can I do this using linq? If so, how? I have never used linq and i've read in several places that using linq instead of a foreach loop is faster... is this true?
Similar to some existing answers, but doing the projection in the query, to make the Sum call a lot simpler:
var sum = (from fee in loan.Items.Fees
where fee.Classification == 806
select fee.SomeValueToSum).Sum();
loan.Item.Fees.
Where(x => x.Classification == 806).
Sum(x => x.SomeValueProperty)
Whether it is faster or not is debatable. IMO, both complexities are the same, the non-LINQ version may be faster.
var q =
from currentFee in loan.Item.Fees
where currentFee.Classification == 806
select currentFee;
var sum = q.Sum(currentFee => currentFee.Fee);
private double get806Fees(Loan loan)
{
return load.Item.Fees.
Where(f => f.Classification == 806).
Sum(f => f.ValueToCalculateSum);
}
I'm assuming here that ValueToCalculateSum is also a double. If it's not then you have to convert it before it is returned.
All of the answers so far are assuming that you're summing up loan.Fees. But the code you actually posted calls Items.Add() to add each Item in loan.Fees.Items to an Items object, and it's that Items object (and not loan.Fees, which is also an Items object) that you say you want to sum up.
Now, if Items is just a simple collection class, then there's no need to do anything other than what people are suggesting here. But if there's some side-effect of the Add method that we don't know about (or, worse, that you don't know about), simply summing up a filtered list of Item objects might not give you the results you're looking for.
You could still use Linq:
foreach (Loan.Fee.Item currentFee in loan.Item.Fees.Where(x => x.Classification == 806)
{
class806.Add(currentFee);
}
return class806.Sum(x => x.Fee)
I'll confess that I'm a little perplexed by the class hierarchy implied here, though, in which the Loan.Item.Fees property is a collection of Loan.Fee.Item objects. I don't know if what I'm seeing is a namespace hierarchy that conflicts with a class hierarchy, or if you're using nested classes, or what. I know I don't like it.