I have the line below but still get an exception "Sequence contains more than one element"
Details rd = this.db.Details.SingleOrDefault(x => x.TId == Id && x.TypeId == TypeId);
I was hoping that SingleOrDefault would avoid the exception.
SingleOrDefault returns a SINGLE element or null if no element is found. If 2 elements are found in your Enumerable then it throws the exception you are seeing. Just like Highlander... with Single - there can be only one.
FirstOrDefault returns the FIRST element it finds or null if no element is found. so if there are 2 elements that match your predicate the second one is ignored.
Assuming you don't care if there are multiple matches and you only want the first one or null if no match is found... then you probably want the following...
Details rd = this.db.Details
.FirstOrDefault(x => x.TId == Id && x.TypeId == TypeId);
Note that both of these methods only return one element they only differ in what they do after they find a match. First stops looking at that point and returns what it found, Single keeps checking the rest of the list to make sure there are no more matches. The OrDefault part determines what it returns if no match is found. SingleOrDefault or FirstOrDefault returns null if no value is found but if you just use Single or First then it MUST find one match or it will throw an exception.
EDIT: Good point Steve
Since First returns the first element you may need to use an OrderBy in order to make sure the element you want is indeed first. For instance... suppose your object had an UpdateDate property and you wanted the object with the most recent UpdateDate...
Details rd = this.db.Details
.OrderByDescending(x => x.UpdateDate)
.FirstOrDefault(x => x.TId == Id && x.TypeId == TypeId);
In case you are having a list, convert the list to IEnumerable list, then you can make use of FirstOrDefault method
IEnumerable<BuyOnlineSearchdetails> details = new List<BuyOnlineSearchdetails>();
var FirstRow = details.FirstOrDefault();
string Count = "0";
if (FirstRow != null)
{
Count = FirstRow.TotalCount.ToString();
}
else
{
Count = "0";
}
You have to use FirstOrDefault() instead of SingleOrDefault().
SingleOrDefault throws an exception if more than one element exists where as FirstOrDefault not.
Related
I need to check if first column in DataGridView contains value 10
I used this
int index = -1;
index = (dgv.Rows.Cast<DataGridViewRow>()
.Where(r => r.Cells[0].Value.Equals(10))
.Select(r => r.Index)).First();
but sometimes produce error: Sequence contains no elements
Someone on this forum sugested to use FirstOrDefault() no First()
Thats work BUT if first column in first row contains value 10
or there are no rows where first column contains value 10, variable index have value 0
My solution was:
try {
index = (dgv.Rows.Cast<DataGridViewRow> ()
.Where(r => r.Cells[0].Value.Equals(10))
.Select(r => r.Index)).First();
} catch {
index = -1
}
Best regards,
I need to check if first column in DataGridView contains value 10
Right tool(method) for the job would be .Any, which returns true if any item from the collection satisfies given condition, or false if not or collection is empty.
if (dgv.Rows.Cast<DataGridViewRow>().Any(r => r.Cells[0].Value.Equals(10)))
{
// exists
}
else
{
// not exist
}
In case you really need an index value, use .DefaultIfEmpty method to return default value for the case when collection is empty or required value not found.
var index = dgv.Rows.Cast<DataGridViewRow>()
.Where(r => r.Cells[0].Value.Equals(10))
.Select(r => r.Index)
.DefaultIfEmpty(-1)
.First();
With .DefaultIfEmpty you can "tell" readers of your code your actual intention without extra conditions or null propagators.
And because you provide default value in case empty collection returned, you can safely use .First() method because at least one item will be always returned.
For finding all occurrences of given value, don't use First or FirstOrDefault.
An alternative is :
int index;
var row = dgv.Rows.Cast<DataGridViewRow>().FirstOrDefault(r => r.Cells[0].Value == 10);
if (row != null)
index = row.Index;
else
index = -1; // or whatever you want
As MSDN says about First():
Returns the first element of a sequence.
The First(IEnumerable) method throws an exception if
source contains no elements. To instead return a default value when
the source sequence is empty, use the FirstOrDefault method.
In addition what MSDN says about FirstOrDefault():
Returns the first element of a sequence, or a default value if no
element is found.
Try to use FirstOrDefault():
int index = -1;
index = (dgv.Rows.Cast<DataGridViewRow>()
.Where(r => r.Cells[0].Value.Equals(10))
.Select(r => r.Index)).FirstOrDefault();
UPDATE:
From "Fixing LINQ Error: Sequence contains no elements":
When you get the LINQ error "Sequence contains no elements", this is
usually because you are using the First() or Single() command rather
than FirstOrDefault() and SingleOrDefault().
You can reproduce your error:
int[] numbers = { };
int first = numbers.First(number => number > 800); // OUTPUT: Sequence contains
// no matching element
If I understood your problem correctly then you are trying to assign first index values which satisfy condition, if there is no record then assign -1 to index.
To solve this issue, you can use null coalescing operator with FirstOrDefault(), like
int index = dgv.Rows.Cast<DataGridViewRow>()
.FirstOrDefault(r => r.Cells[0].Value.Equals(10))?.Index
?? -1;
I have a list of a class object, I need to filter that list with element which starts with these letters "GHB" and then set a listview control dataconext to it to display the elements
if(myList.ToList().FindIndex(x=> x.Name !=null)!=-1 )
{
listview1.DataContext = myList.ToList().where(x=> x.Name.StarstWith("GHB"))
}
But it gives me an error when an element is null
It gives you the error because your if condition is actually useless. You check whether Name in at least one element is not null, if so you try to access the variable. This of course will fail, because you need only 1 element with a valid name and the rest still can have null values which will lead to the NullReferenceException
What you can do is: check in the where clause additionaly whether Name is not null and if so only then check whether it StartsWith("GHB"):
listview1.DataContext = myList.Where(x => x?.Name != null && x.Name.StartsWith("GHB")).ToList();
this way you can save yourself the if condition.
I guess what you where trying to check is if Name in all elements is not null. In this case you can use the All method:
if (myList.All(x=>x.Name != null)
EDIT: using the ? will avoid that Name is checked if an element in the List is entirely null:
myList.Where(x => x?.Name != null && x.Name.StartsWith("GHB")).ToList();
Try this:
listview1.DataContext = myList
.Where(x => x != null
&& !string.IsNullOrEmpty(x.Name)
&& x.Name.StarstWith("GHB"))
.ToList();
...and remove the if statement.
I have a list of points which i have set like this:
List<Node> points = new List<Node>();
I just started to use LINQ to find a particular item in the list based on my search parameters like so:
Node T = points.Where(v => v.x == position[0] && v.y == position[1]);
How ever this gives the error:
Cannot implicitly convert type `System.Collections.Generic.IEnumerable<Node>' to `Node'
So i guess i misunderstood how it works, i presumed it would return the Node in the list that it found or simply null.
What data type is it suppose to be when using Where on a list, am a bit confused.
The extension method Where
Will return multiple items: IEnumerable<Node>
If you expect one item based on your filter, you can use:
Node T = points.FirstOrDefault(v => v.x == position[0] && v.y == position[1]);
If no Node is found for your filter, default(Node) will be returned (that is: null if Node is a class)
There are other extension methods you could use, like:
First(), Single(), SingleOrDefault()
This link will give you details on their characteristics.
.Where returns all points matching your condition.
Instead you need only one point.
Use FirstOrDefault for retrieve only one result.
Try this:
Node T = points.Where(v => v.x == position[0] && v.y == position[1]).FirstOrDefault();`
Where returns IEnumerable<Node> not Node. This is because there could be more than one result.
If you want to return only a single item, use Single, First, or Last instead. If there may be no matching items, use SingleOrDefault, FirstOrDefault, or LastOrDefault.
So, Where returns all matching results, Single returns the only matching result or throws an exception if there are zero or multiple results, and SingleOrDefault return the only matching result, the default value (null, 0, "", etc.) if there are zero results, or throws an exception if there are multiple results.
First and FirstOrDefault are similar to Single and SingleOrDefault except that they will not throw an exception if there are multiple results, rather they will return the first matching value. Last and LastOrDefault works exactly the same, except for the last matching value.
So, assuming you know there is only one matching Node, you would do this:
Node T = points.Single(v => v.x == position[0] && v.y == position[1]);
How do you return a specific type in a Linq query? I know you can use ToList() to return a list of specific objects but how do you return a non list?
MyObj x = from x in list where x.id == 99 select x;
MyObj x = (from x in list where x.id == 99 select x).Single();
if you expect that the id might not exist, then you could use SingleOrDefault to return the default value for the type (probably null in this case).
You could, of course, use First() but I'd be wary, as this could hide errors if you expect to only have one item returned.
MyObj x = list.FirstOrDefault(i=>i.id == 99);
Alternative IEnumerable methods you can use to return a single item:
list.Single(i=>i.id == 99): throws an exception if no matches are found or multiple matches are found.
list.SingleOrDefault(i=>i.id == 99): returns null if no matches are found, throws an exception if multiple matches are found.
list.First(i=>i.id == 99): throws an exception if no matches are found. If multiple matches are found, returns the first item in the list.
list.FirstOrDefault(i=>i.id == 99): returns null if no matches are found. If multiple matches are found, returns the first item in the list.
MyObj x = list.Where(x => x.id == 99).FirstOrDefault();
I'm trying to find the index of the first element of an ArrayList whose 'tag' property does not equal null.
I thought I could do something to the effect of
ArrayList.IndexOf(p => p.tag != null);
or
ArrayList.IndexOf(*.tag != null);
but neither of these work. Is there a way to use IndexOf with just a property of an object?
Try Array.FindIndex:
Searches for an element that matches
the conditions defined by the
specified predicate, and returns the
zero-based index of the first
occurrence within the entire Array.
If you switch to using a generic List instead of ArrayList, you can do this:
int index = list.FindIndex(p => p.tag != null);
Otherwise, you're stuck having to manually (gasp) loop through the array list.
The problem with IndexOf is that you have to use as a parameter an Object in the collection. It is not a LINQ extension. That is why it fails because your lambda is not in the collection.
You could also use the following LINQ query
ArrayList.IndexOf(ArrayList.First( x => p.tag != null ))
But regarding the performance it'll be a bit poor (looking through the collection twice)
You should rather refactor your code as suggested by the smart answers around mine.
If you are wanting to do this while still using the ArrayList you can simply call ToArray() then do your FindIndex
if you know the type of the objects you could do something like this
ArrayList list = ...;
var elem = list.Cast<T>().Select((item,i) => new {item,Index = i}).FirstOrDefault(p => p.item.tag == null);
var index = elem != null ? elem.Index : -1;
will work if you know there's at least one (not that effecient mind you
Cast turns an IEnumerable into a IEnumerable<T> opening up the door to the rest of LINQ
int index = a.Cast<T>()
.Select((p, q) => p != null && p.tag != null ? q + 1 : 0)
.FirstOrDefault(p => p > 0) - 1;
Returns -1 if no element found.