Question

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().

Was it helpful?

Solution

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.

OTHER TIPS

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

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

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

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top