获取数组索引的优雅方式

时间:2012-11-26 19:53:12

标签: c# linq for-loop

我很难通过以下示例切换到LINQ:

int[] inputs = { 5, 3, 5, 66, 4, 5 };
int[] indexes; // I want to have the indexes of '5's in 
               // the inputs array, which is { 0, 2, 5 }

// My way (traditional for loop)

List<int> indexesList = new List<int>();
for (int i = 0; i < inputs.Length; i++)
    if (inputs[i] == 5)
        indexesList.Add(i);

indexes = indexesList.ToArray();

// LINQ way

var indexes = inputs.Select((s, i) => new { i, s })
                    .Where(t => t.s == 5)
                    .Select(t => t.i).ToArray();

问题1。效率(速度,内存使用率)而言,如果我将代码转换为LINQ,我会有什么优势吗?

问题2。如果属实,是否有更强大的优雅方式使用LINQ进行操作?

PS:请注意,在我的真实项目中,这种方法被频繁调用。因此,在速度或内存使用方面略有改进将有助于整个过程。

4 个答案:

答案 0 :(得分:2)

如果您使用LINQ代码,那么您肯定将具有性能优势。通过阅读它很明显:要将每个值与其索引相关联,就会创建一个新对象:

(s, i) => new { i, s }

这些匿名对象除了作为将索引与价值粘合在一起的容器之外别无其他目的;因此,与直接保持计数器相比,所有相关的内存管理都是纯粹的开销。

有人可能会说LINQ提供可读性优势,因为大部分时间它突出了意图而不是机制,但在这个特殊情况下我不认为它比平凡的解决方案更好。

答案 1 :(得分:1)

我会说linq方式实际上效率较低,因为你首先将你的结构转换为元组集合,然后选择索引。

即使它看起来更优雅,我也会说要理解那里到底发生了什么有点困难。

我个人只是推荐迭代。


如果您真的需要提高效率,我建议您尽可能对输入进行排序。第一次对它们进行排序时,需要一些时间,但如果您多次搜索同一列表,它将会收回成本。

答案 2 :(得分:1)

如果你想用LINQ方式做,我建议你实现自己的扩展方法来返回与谓词匹配的元素的索引。

public static IEnumerable<int> IndexesWhere<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate)
{
    int i = 0;

    foreach (TSource element in source)
    {
        if (predicate(element))
            yield return i;

        i++;
    }
}

然后您可以这样称呼它:

var indexes = inputs.IndexesWhere(s => s == 5);

使用这种方法的好处是:

  1. 您可以避免创建匿名类型的实例(与Select((s, i) => new { i, s })方法不同)。
  2. 可以按需枚举序列,这意味着如果您只想执行indexes.Take(2)之类的操作,那么填充整个索引数组会更有效。

答案 3 :(得分:1)

这是一种使用LINQ并避免创建匿名对象的方法。

var indexes = Enumerable.Range(0, inputs.Length)
                        .Where(x => inputs[x] == 5)
                        .ToArray();

它的性能可能类似于使用for循环,但你必须测试它才能确定。