M.D.
M.D.

Reputation: 45

Dynamically projecting with LINQ

Given

(1) A database table, stored as a list of lists. The size of the table in terms of rows and columns is undefined.

List<List<string>> table = new List<List<string>>();

For example:

table.Add(new List<string>() { "a1", "b1", "c1", "d1", "e1" });
table.Add(new List<string>() { "a2", "b2", "c2", "d2", "e2" });
table.Add(new List<string>() { "a3", "b3", "c3", "d3", "e3" });
| a1 | b1 | c1 | d1 | e1 |
| a2 | b2 | c2 | d2 | e2 |
| a3 | b3 | c3 | d3 | e3 |

(2) A list of integers. These integers resemble the indexes of database columns (zero-based), e.g.:

List<int> indexes = new List<int>() { 1, 3, 4 };

Problem

My aim is to project those columns from table of which the indexes occur in the list indexes. Given the above examples, the result should be:

| b1 | d1 | e1 |
| b2 | d2 | e2 |
| b3 | d3 | e3 |

Current Solution

The best I could come up with is to iterate over all rows, like this:

List<List<string>> subtable = new List<List<string>>();
for (int index = 0; index < table.Count; index++)
{
    subtable.Add(table[index].Where((t, i) => indexes.Contains(i)).ToList());
}

Request

A more elegant solution, if possible.

Upvotes: 2

Views: 122

Answers (3)

George Vovos
George Vovos

Reputation: 7618

If you want just to print, it is simpler (and more efficient ) to do it without queries like this:

        List<List<string>> table = new List<List<string>>();
        table.Add(new List<string>() { "a1", "b1", "c1", "d1", "e1" });
        table.Add(new List<string>() { "a2", "b2", "c2", "d2", "e2" });
        table.Add(new List<string>() { "a3", "b3", "c3", "d3", "e3" });

        List<int> indexes = new List<int>() { 1, 3, 4 };

        for (int index = 0; index < table.Count; index++)
        {
            foreach (var columnIndex in indexes)
                Console.Write(table[index][columnIndex] +" ");

            Console.WriteLine();
        }

        Console.ReadLine();

Upvotes: 0

Chris Hinton
Chris Hinton

Reputation: 866

Select all the rows, then for each row filter out the columns that are not in your index list:

var subtable = table
     .Select(row => row.Where((value, colIndex) => indexes.Contains(colIndex)))
     .ToList();

Upvotes: 3

p.s.w.g
p.s.w.g

Reputation: 149050

What about this:

List<List<string>> subtable =
    table.Select(row => indexes.Select(i => row[i]).ToList()).ToList();

In case you need to check the array bounds, you can do this:

List<List<string>> subtable =
    table.Select(row => indexes.Where(i => i >= 0 && i < row.Count)
                               .Select(i => row[i]).ToList()).ToList();

Or if you prefer query syntax:

List<List<string>> subtable =
    (from row in table
     select
     (from i in indexes
      where i >= 0 && i < row.Count
      select row[i]
     ).ToList()
    ).ToList();

Upvotes: 3

Related Questions