C# 查询IEnumerable作为IEnumerable<;类型>;

C# 查询IEnumerable作为IEnumerable<;类型>;,c#,linq,xamarin,C#,Linq,Xamarin,我有一个问题需要有效地解决 我需要IEnumerable源中元素的索引,一种方法是使用下面的 var items = source.Cast<ObjectType>().Where(obj => obj.Start == forDate); 然而,名单可能是巨大的,行动将进行多次。我认为这是低效的,必须有更好的方法来做到这一点 如果有人能为我指出正确的方向,我将不胜感激。有时候,最好忘记Linq,回到最基本的方面: int index = 0; foeach (Ob

我有一个问题需要有效地解决

我需要IEnumerable源中元素的索引,一种方法是使用下面的

    var items = source.Cast<ObjectType>().Where(obj => obj.Start == forDate);
然而,名单可能是巨大的,行动将进行多次。我认为这是低效的,必须有更好的方法来做到这一点


如果有人能为我指出正确的方向,我将不胜感激。

有时候,最好忘记Linq,回到最基本的方面:

int index = 0;

foeach (ObjectType element in source)
{
    if (element.Start == forDate)
    {
        return index;
    }

    index++;
}

// No element found

有时候,最好忘记Linq,回到最基本的方面:

int index = 0;

foeach (ObjectType element in source)
{
    if (element.Start == forDate)
    {
        return index;
    }

    index++;
}

// No element found

使用Linq,可以在过滤每个对象之前获取它们的索引:

source
    .Cast<ObjectType>()
    .Select((obj, i) => new { Obj = obj, I = i })
    .Where(x => x.Obj.Start == forDate)
    .Select(x => x.I)
    .FirstOrDefault();

使用Linq,可以在过滤每个对象之前获取它们的索引:

source
    .Cast<ObjectType>()
    .Select((obj, i) => new { Obj = obj, I = i })
    .Where(x => x.Obj.Start == forDate)
    .Select(x => x.I)
    .FirstOrDefault();

您的第二个代码示例无效:由于
items
是一个
IEnumerable
,因此无法调用
items[0]
。您可以使用
First()
。无论如何:

var items = source.Cast<ObjectType>()
.Select((item, index) => new KeyValuePair<int, ObjectType>(index, item))
.Where(obj => obj.Value.Start == forDate);

您的第二个代码示例无效:由于
items
是一个
IEnumerable
,因此无法调用
items[0]
。您可以使用
First()
。无论如何:

var items = source.Cast<ObjectType>()
.Select((item, index) => new KeyValuePair<int, ObjectType>(index, item))
.Where(obj => obj.Value.Start == forDate);

如果您需要多次执行此操作,我将创建索引查找

ILookup<DateTime, int> lookup =
    source
        .Cast<ObjectType>()
        .Select((e, i) => new { e, i })
        .ToLookup(x => x.e.Start, x => x.i);
由于
查找
基本上类似于返回多个值的字典,因此您可以立即得到结果。因此,对多个值重复此操作非常快


由于这将返回
IEnumerable
,因此您知道
列表中何时存在重复值。如果您只需要第一个,那么只需执行
.first()

如果您需要多次执行此操作,我将创建索引的查找

ILookup<DateTime, int> lookup =
    source
        .Cast<ObjectType>()
        .Select((e, i) => new { e, i })
        .ToLookup(x => x.e.Start, x => x.i);
由于
查找
基本上类似于返回多个值的字典,因此您可以立即得到结果。因此,对多个值重复此操作非常快



由于这将返回
IEnumerable
,因此您知道
列表中何时存在重复值。如果您只需要第一个,那么只需执行一个
.first()

您无法有效地使用
IEnumerable
执行此操作。这就是为什么我们有其他接口,比如
ICollection
。例如,
IEnumerable
可以通过数据库连接/ORM实现,也可以通过LinkedList实现。这两种方法都不能实现有效的算法。@Aron-但是,如果基础类型也是
ICollection
,那么LINQ会在可能的情况下使用有效的方法。感谢所有发布答案的人。很多都是未来很好的参考。但是,在本例中,由于实现的特殊性,我实现了一个二进制搜索。这就是为什么我们有其他接口,比如
ICollection
。例如,
IEnumerable
可以通过数据库连接/ORM实现,也可以通过LinkedList实现。这两种方法都不能实现有效的算法。@Aron-但是,如果基础类型也是
ICollection
,那么LINQ会在可能的情况下使用有效的方法。感谢所有发布答案的人。很多都是未来很好的参考。但是,在本例中,由于实现的细节,我实现了二进制搜索。为什么使用
KeyValuePair(index,item)
?为什么不仅仅是
new{index,item}
?@Enigmativity,因为它是一个结构,而是您喜欢的任何东西。我想这并不重要。
struct
为什么有帮助?@Enigmativity在这种情况下,这并不重要,因为你只拿了第一项。但是,如果你要枚举一百万个项目,它将避免创建一百万个对象。(我使用了
KeyValuePair
,这是一种反射,我没有考虑使用匿名类型)请记住
KeyValuePair
没有实现
Equals
&
GetHashCode
,因此它不能用于许多需要比较的运算符。匿名类型确实实现了它们。最好避免使用
KeyValuePair
。为什么要使用
KeyValuePair(索引,项目)
?为什么不仅仅是
new{index,item}
?@Enigmativity,因为它是一个结构,而是您喜欢的任何东西。我想这并不重要。
struct
为什么有帮助?@Enigmativity在这种情况下,这并不重要,因为你只拿了第一项。但是,如果你要枚举一百万个项目,它将避免创建一百万个对象。(我使用了
KeyValuePair
,这是一种反射,我没有考虑使用匿名类型)请记住
KeyValuePair
没有实现
Equals
&
GetHashCode
,因此它不能用于许多需要比较的运算符。匿名类型确实实现了它们。最好避免使用
KeyValuePair
。对,将它们编入索引。这与ToDictionary()有何不同?@bit-它的不同之处在于字典仅将键映射到单个值,而这将任何键映射到零或多个值(从而获得重复值的所有索引)。如果使用不存在的键进行查找,则会得到一个空的可枚举项,而不是一个异常。这与ToDictionary()有何不同?@bit-它的不同之处在于字典仅将键映射到单个值,而这将任何键映射到零或多个值(从而获得重复值的所有索引)。如果使用不存在的键执行查找,则会得到一个空的可枚举项,而不是一个异常。我已经实现了二进制搜索,这可以避免将列表中的所有项强制转换为所需类型的需要,并减少操作的内存开销。有时最好忘记Linq。我实现了一个二进制搜索,这样可以避免将列表中的所有项强制转换为所需的类型,并减少操作的内存开销。有时候忘记林克是件好事。