I have a IQueryable which is ordered by some condition. Now I want to know the position of a particular element in that IQueryable. Is there a linq expression to get that. Say for example there are 10 elements in the IQueryable and the 6th element matches a condition, I want to get the number 6.
+2
A:
You could use something like query.TakeWhile(x => !matchesCondition(x)).Count()
, though that has the effect of enumerating the preceding values, which may not be what you want.
camccann
2009-12-08 19:44:04
You have to enumerate through those preceding values anyway, haven't you?
treaschf
2009-12-08 20:04:02
Interesting solution. It would be OK to enumerate the preceding values if it were a memory object, but not for a DB. Note that if the element is not in the list, this function returns the length of the list. Normally you would expect such functions to return -1 or perhaps null.
Mark Byers
2009-12-08 20:04:32
@Mark Byers: I read the question's phrasing as implying that the desired element was known to be present, and only the position was desired; and the DB scenario was indeed my concern about enumerating.In practice I suspect that doing this to an IQueryable is unwise, but as a quick hack this approach is at least succinct and understandable.
camccann
2009-12-08 20:17:14
+5
A:
First select each item with its index, then filter the items, and finally extract the original index:
var result = orderedList
.Select((x, i) => new { Item = x, Index = i })
.Where(itemWithIndex => itemWithIndex.Item.StartsWith("g"))
.FirstOrDefault();
int index= -1;
if (result != null)
index = result.Index;
Test bed:
class Program
{
static void Main(string[] args)
{
var orderedList = new List<string>
{
"foo", "bar", "baz", "qux", "quux",
"corge", "grault", "garply", "waldo",
"fred", "plugh", "xyzzy", "thud"
}.OrderBy(x => x);
// bar, baz, corge, foo, fred, garply, grault,
// plugh, quux, qux, thud, waldo, xyzzy
// Find the index of the first element beginning with 'g'.
var result = orderedList
.Select((x, i) => new { Item = x, Index = i })
.Where(itemWithIndex => itemWithIndex.Item.StartsWith("g"))
.FirstOrDefault();
int index= -1;
if (result != null)
index = result.Index;
Console.WriteLine("Index: " + index);
}
}
Output:
Index: 5
Mark Byers
2009-12-08 19:47:47
A:
var query = new List<string>{ "a", "b", "c" };
int x = 0;
var index = (from item in query
let dummy = ++x
where item == "b"
select x).FirstOrDefault() - 1;
if (index == -1)
Console.WriteLine("Not found");
else
Console.WriteLine(index);
Hasan Khan
2009-12-08 19:54:13
A:
You can also use the verson of the "Where" function that incldes the collection index as a parameter to the predicate function. See MSDN for more info.
var result = Enumerable.Range(0, 10).Where((x, i) => i == 6);
The version could result in an empty list if there isn't a 6th element. Also this doesn't evaluate the where clause until you iterate over the result.
Jason
2009-12-08 22:57:05