0

mI am comparing Listview items with Generic List items with List.Any Method like this:

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

Please tell me, how to get InvalidSheets list index which was matched with itemRow.Tag.ToString().

4

5 回答 5

5

You can do this

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

if you want to get the object directly then do this

 var matchedObject = InvalidSheets.FirstOrDefault(x => x != null && x.FilePath == itemRow.Tag.ToString());
于 2013-08-23T08:01:31.383 回答
5

Since there seems some debate about how much faster it would be to use List.FindIndex() instead of Linq to find the index, I wrote a test program.

This assumes that you only care about finding the index of the first matching item in a list. It doesn't handle multiple matching items.

Also note that this test is worst-case in that the matching item is at the very end of the list.

My results for an x86 release build (run on Windows 8 x64, quad core processor):

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

showing that List.FindIndex() is roughly four times faster than using Linq.

Here's the test code:

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);
        }
    }
}

So given that List.FindIndex() is both much faster AND much easier to read than using the Linq, I can see no reason to use Linq to solve this particular problem.

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

versus

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

The first version wins on all counts IMO.

于 2013-08-23T11:09:01.590 回答
3

Here is how you can get the index:

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

However you might want to refactor this with FirstOrDefault like this:

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;
    }
}
于 2013-08-23T08:00:57.280 回答
1

Try this:

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

It will get index of first invalid sheet matching the predicate

于 2013-08-23T08:00:26.080 回答
0

You can project the index with the overload, therefore you need to select an anonymous type:

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
于 2013-08-23T08:03:59.143 回答