September 29, 2020

Linq GroupBy/ToLookUp

These are Linq methods to group elements in a sequence. ToLookup() is the same as GroupBy(); the only differences are that GroupBy execution is deferred, whereas ToLookup() execution is immediate and also ToLookup() is not available in linq query form only the method form.

Note that the resultant group object exposes itself in 2 ways:

1. A 'Key' property exposes a value which all the items in the group have in common (this could be a calculated value)

2. The group object itself is an IEnumerable of the items in the group.

This operation will iterate over all the items in the enumeration. Works well with the Linq method "ToDictionary()" to convert a sequence into a dictionary.

Here is an example:

// Read StationLocationRaw(s) (int StationId and string Location)
// from the Station Locations file
public class StationLocationReader 
{
    FileInfo fi;
    public StationLocationReader(string path)
    {
        fi = new FileInfo(path);
    }

    public IDictionary<int, string> StationLocationsByStationId()
    {
        var stationLocationsDictionary =
            ReadStationLocations(). // returns StationLocationRaw(s)
                                    // (int StationId and string Location)
            GroupBy(s => s.StationId).
            ToDictionary(g => g.Key, g => g.Single().Location ?? "");
        return stationLocationsDictionary;
    }

    public IEnumerable<StationLocationRaw> ReadStationLocations()
    {
        Debug.Assert(fi.Exists);
        var stationLocations = fi.
            ReadLines().
            Skip(1). // Skip the header line
            Select(line => ExtractStationLocation(line));
        return stationLocations;
    }

    private StationLocationRaw ExtractStationLocation(string line)
    {
        var stationLocation = new StationLocationRaw();
        var parts = line.Split('\t');
        if (parts.Length >= 2)
        {
            // ParseInt is an extension method to convert
            // to a string to an integer, returning 0 
            // when the string is invalid.
            stationLocation.StationId = parts[0].Trim().ParseInt(0); 
            stationLocation.Location = parts[1].Trim();
        }
        return stationLocation;
    }
}

No comments: