Miłosz Synecki
Miłosz Synecki

Reputation: 45

How to query a objects from a list with giving a list of ids

I have a list of object ids that I would like to retrieve from another list of object that every object has his own unique id.

List<string> idList

List<ObjectWithId> objectList

class ObjectWithId
{ 
    string Id; 
    ...
}

I know how to do it one by one. But is it possible to do it in one line using LINQ?

Upvotes: 1

Views: 1247

Answers (2)

steve16351
steve16351

Reputation: 5812

There are a number of ways you could do this, but you need to be careful if performance is a consideration.

For example, in addition to a simple Where, you could use the Join operator as follows to find the matching objects:

var objects = Enumerable.Range(0, 1000)
        .Select(a => new ObjectWithId() { Id = a.ToString() })
        .ToList();

var ids = Enumerable
    .Range(0, 1000 / 2).Select(a => a.ToString())
    .ToList();

var matchedObjects = objects.Join(
                inner: ids,
                outerKeySelector: a => a.Id,
                innerKeySelector: a => a,
                resultSelector: (objectWithId, id) => objectWithId)
                .ToList();

If I contrast the performance of the above with the .Where operator:

objects.Where(m => ids.Contains(m.Id)).ToList();

On my computer I see this:

+--------------+-----------+--------------------+-------------------+-------------------+-------+
| Method       | N         |               Mean |             Error |            StdDev |  Rank |
+--------------+-----------+--------------------+-------------------+-------------------+-------+
| LinqJoin     | 10        |           997.5 ns |         18.938 ns |         17.714 ns |   2   |
+--------------+-----------+--------------------+-------------------+-------------------+-------+
| LinqWhere    | 10        |           793.2 ns |          9.905 ns |          8.271 ns |   1   |
+--------------+-----------+--------------------+-------------------+-------------------+-------+
| LinqJoin     | 1000      |       103,635.0 ns |      1,049.670 ns |        930.505 ns |   3   |
+--------------+-----------+--------------------+-------------------+-------------------+-------+
| LinqWhere    | 1000      |     2,873,539.1 ns |     49,073.330 ns |     45,903.223 ns |   5   |
+--------------+-----------+--------------------+-------------------+-------------------+-------+
| LinqJoin     | 10000     |     1,002,157.5 ns |     12,564.510 ns |     11,138.111 ns |   4   |
+--------------+-----------+--------------------+-------------------+-------------------+-------+
| LinqWhere    | 10000     |   283,998,696.5 ns |  4,953,233.368 ns |  4,633,257.566 ns |   6   |
+--------------+-----------+--------------------+-------------------+-------------------+-------+

In otherwords, .Where outperforms .Join when there are 10 objects, marginally. By the time we get to 1000 objects, .Join is outperforming it by a factor of nearly 28 - and at 10,000, by a factor of more than 280.

This is because Join will create an index in advance of all the keys from the object and in the list it is being joined for, internally probably using a hash. This means as it iterates the outer list, a simple lookup to this index can be done to locate a match. However, with the .Where and .Contains approach, this is essentially a nested list, with worst case O(N^2) complexity. It can only compete when there are a small numbers of items in the list, because .Join has the overhead of creating the index.

Upvotes: 2

Afshin Rashidi
Afshin Rashidi

Reputation: 353

use this:

objectList.Where(m=> idList.Contains(m.Id)).ToList();

Upvotes: 7

Related Questions