LordTitiKaka
LordTitiKaka

Reputation: 2156

replace List.foreach to LINQ

I'm new to LINQ and doing some experiments with it.

Sorry if it is a duplicate but I cant seem to find proper guide (for me) to it

I want to replace this code :

DataTable table
List<string> header = new List<string>();
table.Columns.Cast<DataColumn>().ToList().ForEach(col => header.Add(col.ColumnName));

with something LINQ like:

var LINQheader = from mycol in table.Columns select mycol.ColumnName;
LINQheader.tolist();

but it doesn't even compile. what I want Is not a one line solution but would like some logic to understand how construct it with more complicated environments (Like choosing many node in XML with some logic)

Upvotes: 5

Views: 1286

Answers (6)

Hamid Pourjam
Hamid Pourjam

Reputation: 20754

here is the original code

table.Columns.Cast<DataColumn>().ToList().ForEach(col => header.Add(col.ColumnName));

Why Cast used?
because it allows you to treat DataColumnCollection items as a DataColumn not an object.

Why ToList used?
becuase it converts your IEnumerable to List and allows you to call ForEach because this function is special method that exists in List class.

Why ForEach used?
because it allows you to do what you want for each element on the list (in your case it adds column name of each column to another list(header)).

Simplified version:

now assume you want to add column names to header where they starts with "Student" you can write something like this

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

foreach (DataColumn col in table.Columns)
{
    if (col.ColumnName.StartsWith("Id")) // you can remove this line if you want to add all of them
       header.Add(col.ColumnName);
}

you can also use this

table.Columns.Cast<DataColumn>()
    .ToList()
    .ForEach(col =>
    {
        if (col.ColumnName.StartsWith("Id"))
            header.Add(col.ColumnName)
    });

or

var headers = table.Columns.Cast<DataColumn>()
        .Where(col => col.ColumnName.StartsWith("Id"))
        .Select(col => col.ColumnName);

header.AddRange(headers);

Upvotes: 3

mybirthname
mybirthname

Reputation: 18127

    static void Main(string[] args)
    {
        DataTable tbl = new DataTable();
        tbl.Columns.Add("A");
        tbl.Columns.Add("B");

        var p = from DataColumn col in tbl.Columns select col.ColumnName;

        foreach(string a in p)
        {
            Console.WriteLine(a);
        }
    }

Here little code example. If you want to be List<string>, use ToList().

EDIT:

Like @Grundy says you missing to specify type of the col, which is DataColumn.

List<string> columnList = (from DataColumn mycol in table.Columns select mycol.ColumnName).ToList();

Here this will be your one line.

Upvotes: 2

VMAtm
VMAtm

Reputation: 28345

var LINQheader = from mycol in table.column select mycol.ColumnName;
LINQheader.tolist();

This will not compile as there is no such property in DataTable as column, there is only Columns, and you have to use .Cast() method as they are not implementing right interface (see @Uriil's answer).

Try this:

var LINQheader = from mycol in table.Columns.Cast<DataColumn>()
                  select mycol.ColumnName;
LINQheader.tolist();

If you want to use wrap it in an extension method, you can do it like this:

public static IEnumerable<string> GetHeaderColumns (this DataTable dataTable) 
{
    if (dataTable == null || !dataTable.Columns.Any())
    {
        yield break;
    }
    foreach (var col in dataTable.Columns.Cast<DataColumn>())
    {
        yield return col.ColumnName;
    }
}

Upvotes: 2

Uriil
Uriil

Reputation: 12618

You have some problems, which requires workaround:

  1. ForEach is List specifict method, so can can not translate it into LINQ
  2. LINQ is for data selection, aggregation, but not for data modification
  3. table.Columns, returns DataColumnCollection, which does not implement IEnumerable<T>, so you will have to cast it anyway:

    var LINQheader = from mycol in table.Columns.Cast<DataColumn>()
                     select name.ColumnName;
    

Upvotes: 1

Grundy
Grundy

Reputation: 13381

Why not simple select like

DataTable table;
IEnumerable<string> header = from mycol in table.Columns.Cast<DataColumn>()
                             select mycol.ColumnName;

Upvotes: 1

dbc
dbc

Reputation: 116585

You can use Enumerable.Aggregate() for this:

var header = table.Columns.Cast<DataColumn>().Aggregate(new List<string>(), (list, col) => { list.Add(col.ColumnName); return list; });

In general, Linq allows for retrieval and transformation of sequences of data from data sources. What you want to do in this question is to iterate over a sequence and return an immediate result. That isn't the primary focus of Linq, but there are methods that perform tasks like this, including Aggregate(), Average(), Count(), Max() and so on.

Upvotes: 3

Related Questions