Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am tracking trains and trying to identify individual trains seen multiple times at different points through the IDs of the wagons on them when spotted.

// create a lookup of all tracked trains for each wagon
IEnumerable<Train> trains = GetTrains();

var wagonTrains = new Dictionary<int, List<Train>>();
foreach (Train t in trains)
{
  foreach (int w in t.WagonsInTrain)
  {
    if (!wagonTrains.ContainsKey(w))
    {
      wagonTrains.Add(w, new List<Train>());
    }
    wagonTrains[w].Add(t);
  }
}

Is there a better way do to what I am doing in this code segment? Perhaps some chained linq operations? Is there a particular name for the kind of operation I am using here?

share|improve this question
up vote 5 down vote accepted

create a lookup of all tracked trains for each wagon

That's pretty much what the ToLookup() method is for. You just need a bit more LINQ to get a collection of (train, wagon) pairs, so that ToLookup() can work:

var wagonTrains =
    (from train in trains
     from wagon in train.WagonsInTrain
     select new { train, wagon })
        .ToLookup(x => x.wagon, x => x.train);
share|improve this answer

Here is one that uses chained linq operations:

var trainsByWagon =
    trains
        .SelectMany(train => train.WagonsInTrain, (train, wagon) => new { train, wagon })
        .GroupBy(trainAndWagon => trainAndWagon.wagon, trainAndWagon => trainAndWagon.train);
        .ToDictionary(g => g.Key, g => g.ToList());

Small print: Haven't actually tried this, but should work.

share|improve this answer
    
Sorry, I eventually accepted the chronologicaly first answer, but both are super useful. – Michael Sandler Jul 25 '13 at 15:37

I've actually set this up in my code as a pair of extension methods:

public static class IDictionaryExtensions
{
    public static void Update<TKEY, TVALUE>(this IDictionary<TKEY, TVALUE> dictionary, TKEY key, TVALUE value)
    {
        if (dictionary.ContainsKey(key))
        {
            dictionary[key] = value;
        }
        else
        {
            dictionary.Add(key, value);
        }
    }
    public static void AddToList<TKEY, TVALUE>(this IDictionary<TKEY, IList<TVALUE>> dictionary, TKEY key, TVALUE value)
    {
        if (dictionary.ContainsKey(key) && dictionary[key] != null)
        {
            dictionary[key].Add(value);
        }
        else
        {
            dictionary.Update(key, new List<TVALUE> {value});
        }
    }
 }

The first method is an all-purpose "Add"-type method which will either add it or update it depending on whether or not it exists. The second is specifically for dictionaries where the value is a List<>. It'll let you add an element to the List<>, creating the key if neccesary.


For your example, usage would be:

IEnumerable<Train> trains = GetTrains();
var wagonTrains = new Dictionary<int, List<Train>>();
foreach (var train in trains)
{
   foreach (var wagon in train.WagonsInTrain)
   {
       wagonTrains.AddToList(wagon, train);
   }
}
share|improve this answer
    
Your code wouldn't compile, AddToList() has two parameters. – svick Jul 25 '13 at 17:49
    
@svick - Good catch. That's what I get for freehanding it. Fixed. – Bobson Jul 26 '13 at 13:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.