Blog from Saravanan Arumugam

Let us talk about Technologies

Category Archives: Linq

Read a CSV file with Linq


I just wanted to post a small code snippet, for future reference, that reads a CSV file into List of string arrays.

rawFile = (from line in File.ReadAllLines(fileName).AsParallel()
            select line.Split(',')).ToList();

File.ReadAllLines() reads all the lines from the csv into array of comma separated strings. Each line is split based on the comma into an array of strings. AsParallel() attempts to process the whole operation with multiple parallel threads.

User friendly name for Enumeration fields


Unlike class’s properties, showing user friendly display name for an enumeration field is not that easy.

For example, I would like to use the following Enum. But when I display them on screen, I want to display “Prior Record” instead of “PriorRecord”, and “Future Record” instead of “FutureRecord”.

public enum RecordStatus
{
   New = 0,

   Error = 1,

   PriorRecord = 2,

   FutureRecord = 4,

   ExcessHours = 8,
}

I tried to use DisplayNameAttribute, but its not applicable to Enums and Fields. So I had to do something equivalent to it.

1. Create Custom Attribute to specify friendly names

First thing to do is to create a custom attribute which I can use to specify the Display Name of each field. We can take advantage of DisplayNameAttribute by deriving the custom type from it. DisplayNameAttribute has all infrastructure already specified. We just need to create a class with constructors.

[AttributeUsage(AttributeTargets.Field)]
public class EnumDisplayNameAttribute : DisplayNameAttribute
{
    public EnumDisplayNameAttribute()
        : base()
    {
 
    }
 
    public EnumDisplayNameAttribute(string displayName)
        : base(displayName)
    {
 
    }
}

Note that I have placed an AttributeUsageAttribute to make this attribute available for fields.

 

2. Use the custom attribute on the Enum fields

Next thing to do is to use the attribute to specify the friendly name.

[Flags]
public enum RecordStatus
{
	New = 0,
 
	Error = 1,
 
	[EnumDisplayName("Prior Record")]
	PriorRecord = 2,
 
	[EnumDisplayName("Future Record")]
	FutureRecord = 4,
 
	[EnumDisplayName("Excess Hours")]
	ExcessHours = 8,
}

 

3. Write an extension method to Enum

Next thing is to show the DisplayName whenever Enum.ToString() is called. We have to write an overload to the ToString() as an extension.

public static class EnumExtension
{
/// <summary>
/// Shows the user friendly name specified in EnumDisplayNameAttribute
/// </summary>
/// <param name="enumeration">Enumeration object</param>
/// <param name="indicator">An indicator to enable this extension. 
/// Pass any integer as indicator.</param>
/// <returns>User friendly name of the Enumeration</returns>
public static string ToString(this Enum enumeration, bool indicator)
{
    string returnValue = enumeration.ToString();
 
    if (indicator)
    {
        //Flagged enumeration will have comma separated value.
        //Split them into multiple values before use.
        var displayValues =
           //Split is made here to handle all the comma separated enum values
            from enumValue in enumeration.ToString().Split(',')
            //Join is made here to work with field object instead of string.
            join field in enumeration.GetType().GetFields()
            on enumValue.Trim() equals field.Name
            select field
                into enumFields
                //If the field has the EnumDisplayAttribute, display it;
                //otherwise, display the regular field name.
                //Conditional output is done through the ternary operator.
                select
                (enumFields.GetCustomAttributes(false).Any(attribute =>
                    attribute is EnumDisplayNameAttribute) ?
                (from attribute in enumFields.GetCustomAttributes(false)
                    where attribute is EnumDisplayNameAttribute
                    select ((EnumDisplayNameAttribute)attribute).DisplayName)
                    .First()
                : enumFields.Name);
 
        if (displayValues.Count() > 0)
            returnValue = string.Join(", ", displayValues);
    }
    return returnValue;
}
}

Note that the ToString() method contains a Boolean indicator. If it is true, the ToString() would return the friendly names else will return the defaults.

The linq statement in the method has 3 levels of loops.

Loop 1. Since the enum is marked with FlagAttribute, the default ToString() may produce comma separated values such as Error, ExcessHours, FutureRecord. So in the linq we split them into an array of strings.

Loop 2. Find the FieldInfo object based on the string we received from the previous loop.

Loop 3. If the field has EnumDisplayNameAttribute, return the DisplayName. If the field doesn’t have the custom attribute, return the FieldInfo.Name.

 

4. Use the overloaded ToString() method

Now in the places where we need the friendly name, start using the ToString(true).

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(
            (RecordStatus.Error 
            | RecordStatus.ExcessHours).ToString(true));
        Console.WriteLine(
            RecordStatus.ExcessHours 
            | RecordStatus.FutureRecord);
    }
}

image

Chaining the result in Linq


In linq, extension method is a nice way to chain the result of one query to another and so on.

For example

var fileData = File.ReadAllLines(this.FileName)
                        .Select(line => line.Split('.'))
                        .Select(columns => new
                        {
                            Column1 = columns[0],
                            Column2 = columns[1],
                            Column3 = columns[2],
                            Column4 = columns[3]
                        }
                        );

In the example above, the result of first select goes as the input to the next select and this operation can go seamlessly to any level.

For writing the same query in the sugared linq syntax (with from … select syntax), you can take two approaches.

1. Use let keyword

let keyword can introduce a new variable in addition to the iteration variable and can appear in the middle of the query.

var fileData = (from line in File.ReadAllLines(file)
             let columns = line.Split(',')
             select new
             {
                 Column1 = columns[0],
                 Column2 = columns[1],
                 Column3 = columns[2],
                 Column4 = columns[3]
             }).ToList();

2. Use into keyword

into keyword is an ideal replacement of extension method based example shown above. into brings the result of a query operation to an intermediate queryable result set, which can further be queried.

var fileData1 = (from line in File.ReadAllLines(file)
                 select line.Split(',')
                     into columns
                     select new
                     {
                         Column1 = columns[0],
                         Column2 = columns[1],
                         Column3 = columns[2],
                         Column4 = columns[3]
                     }
                         // just to show that this can be 
                         // exetended to any level
                         into someNewResultSet 
                         select someNewResultSet
                     ).ToList();

Index in IEnumerable


When we use the IEnumerable interface, its usually hard to get the index of the item.

For example, I need to display a dropdown list in a page that uses MVC 3. I can use the CurrentCulture class to get the array of month names. But I want to set the integer as the value representing the month.

<select id="MonthSelection" name="MonthSelection">
    <option value="1">Jan</option>
    <option value="2">Feb</option>
    <option value="3">Mar</option>
    <option value="4">Apr</option>
    <option value="5">May</option>
    <option value="6">Jun</option>
    <option value="7">Jul</option>
    <option value="8">Aug</option>
    <option value="9">Sep</option>
    <option value="10">Oct</option>
    <option value="11">Nov</option>
    <option value="12">Dec</option>
    <option value="13"></option>
</select>

The choice I had was this. I couldn’t use the foreach since it would not provide me the ability to get the index of the item. So I am left with for() loop. However, look at the code below, isn’t that too much of coding for a simple thing?

Dictionary<int, string> months = new Dictionary<int, string>();

for (int index = 0;

    index < CultureInfo.CurrentCulture

        .DateTimeFormat

        .AbbreviatedDayNames.Count();

        index++)

{

    months.Add(index + 1,

        CultureInfo.CurrentCulture

        .DateTimeFormat

        .AbbreviatedDayNames[index]);

}

 

Using the for() loop is not comfortable all the time.

 

Solution

Linq provides a solution to this situation. In a IEnumerable, if you want the index of the item, use the projection (Select) with a second parameter to the lambda expression. The second parameter is usually the index of the item in the collection.

CultureInfo.CurrentCulture.DateTimeFormat
.AbbreviatedMonthNames.Select((month, index) 
           => new { Key = index + 1, Value = month })

Now the whole code show on the previous example is shrunk to a single line. Isn’t that great from Linq?