列表<T>.Any();如何获取匹配项的索引?

问题描述 投票:0回答:5

我正在使用

List<T>.Any()
方法将 Listview 项目与通用列表项目进行比较,如下所示:

foreach (ListViewItem itemRow in lstviewAddsheets.Items)
{
    if (InvalidSheets.Any(x => x != null && x.FilePath == itemRow.Tag.ToString()))
    {
        // Match found
    }
}

请告诉我,如何获取与

itemRow.Tag.ToString()
匹配的InvalidSheets列表索引。

c# list generics any
5个回答
5
投票

由于似乎存在一些关于使用

List.FindIndex()
而不是 Linq 来查找索引要快多少的争论,因此我编写了一个测试程序。

这假设您只关心查找列表中第一个匹配项的索引。它不处理多个匹配的项目。

另请注意,此测试是最坏的情况,因为匹配项位于列表的最末尾。

我的 x86 发布版本结果(在 Windows 8 x64、四核处理器上运行):

Calling Via FindIndex() 100 times took 00:00:00.9326057
Calling Via Linq 100 times took 00:00:04.0014677
Calling Via FindIndex() 100 times took 00:00:00.8994282
Calling Via Linq 100 times took 00:00:03.9179414
Calling Via FindIndex() 100 times took 00:00:00.8971618
Calling Via Linq 100 times took 00:00:03.9134804
Calling Via FindIndex() 100 times took 00:00:00.8963758

表明

List.FindIndex()
大约比使用 Linq 快四倍。

这是测试代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Demo
{
    class Test
    {
        public string FilePath;
    }

    class Program
    {
        private void run()
        {
            int count = 1000000;

            List<Test> list = new List<Test>(count);

            for (int i = 0; i < count; ++i)
                list.Add(new Test{ FilePath = i.ToString()});

            string target = (count-1).ToString();

            for (int trial = 0; trial < 4; ++trial)
            {
                Action viaFindIndex =
                (
                    () =>
                    {
                        int index = list.FindIndex(x => (x != null) && (x.FilePath == target));
                    }
                );

                Action viaLinq =
                (
                    () =>
                    {
                        int index = list.Select((x, i) => new { Item = x, Index = i })
                        .First(x => (x != null) && (x.Item.FilePath == target))
                        .Index;
                    }
                );

                viaFindIndex.TimeThis("Via FindIndex()", 100);
                viaLinq.TimeThis("Via Linq", 100);
            }
        }

        private static void Main()
        {
            new Program().run();
        }
    }

    static class DemoUtil
    {
        public static void TimeThis(this Action action, string title, int count = 1)
        {
            var sw = Stopwatch.StartNew();

            for (int i = 0; i < count; ++i)
                action();

            Console.WriteLine("Calling {0} {1} times took {2}", title, count, sw.Elapsed);
        }
    }
}

因此,考虑到

List.FindIndex()
比使用 Linq 更快且更容易阅读,我认为没有理由使用 Linq 来解决这个特定问题。

int index = list.FindIndex(x => (x != null) && (x.FilePath == target));

int index = list.Select((x, i) => new { Item = x, Index = i })
            .First(x => (x != null) && (x.Item.FilePath == target))
            .Index;

在我看来,第一个版本在所有方面都获胜。


5
投票

你可以这样做

 int index =   InvalidSheets.FindIndex(x => x != null && x.FilePath == itemRow.Tag.ToString());

如果你想直接获取对象那就这样做

 var matchedObject = InvalidSheets.FirstOrDefault(x => x != null && x.FilePath == itemRow.Tag.ToString());

3
投票

以下是获取索引的方法:

var index = InvalidSheets.Select((x, i) => new {Item = x, Index = i})
                         .First(x => x.Item != null && x.Item.FilePath == itemRow.Tag.ToString())
                         .Index;

但是您可能想用

FirstOrDefault
重构它,如下所示:

foreach (ListViewItem itemRow in lstviewAddsheets.Items)
{
    var sheet = InvalidSheets.Select((x, i) => new {Item = x, Index = i})
                             .FirstOrDefault(x => x.Item != null && x.Item.FilePath == itemRow.Tag.ToString());
    if (sheet != null)
    {
       var index = sheet.Index;
    }
}

1
投票

试试这个:

InvalidSheets.IndexOf(InvalidSheets.First(x => x != null && x.FilePath == itemRow.Tag.ToString()))

它将获取与谓词匹配的第一个无效工作表的索引


0
投票

您可以使用重载来投影索引,因此您需要选择匿名类型:

var invalids = InvalidSheets.Select((s, i) => { Sheet=s, Index=i })
    .Where(x => x.Sheet != null && x.Sheet.FilePath == itemRow.Tag.ToString()));
bool anyInvalid = invalids.Any(); // is any invalid
IEnumerable<int> indices = invalids.Select(x => x.Index);// if you need all indices
© www.soinside.com 2019 - 2024. All rights reserved.