将配对列表转换为一对多查找

时间:2012-10-24 11:23:20

标签: c#-4.0 linq-to-objects lookup-tables

我有成对字符串的列表(长度相等),称之为“source”和“target”。一个源可以映射到多个目标。我可以使用LINQ将其转换为查找表(将源映射到目标列表)吗?一个(冗长的)这样做的方式是:

// There may be multiple targets corresponding to each source
// as in the following example lists.
// NB. Lists are guaranteed same length
List<string> sourceNames = new List<string>() { "A", "B", "C", "A", "B", "C" };
List<string> targetNames = new List<string>() { "Z", "Y", "X", "W", "V", "U" };

// Use extension methods to make list of unique source names
List<string> uniqueSourceNames = sourceNames.Distinct().ToList<string>();

// For each unique source, make a list of the corresponding targets
Dictionary<string, List<string>> nameLookup = new Dictionary<string, List<string>>();
foreach (string sourceName in uniqueSourceNames)
{
    List<string> targetsForSource = new List<string>();

    for (int index = 0; index < sourceNames.Count; index++)
    {
        if (sourceNames[index] == sourceName)
            targetsForSource.Add(targetNames[index]);
    }
    nameLookup.Add(sourceName, targetsForSource);
}

// Can now use the nameLookup dictionary to map a source name to a list of target names
// e.g. this returns "Z", "W"
List<string> targets = nameLookup["A"];

有没有办法使用LINQ更有效地做到这一点?

2 个答案:

答案 0 :(得分:1)

您可以使用GroupByToDictionary

var lookup = sourceNames
   .Select((Source, i) => new { Target = targetNames.ElementAt(i), Source})
   .GroupBy(x => x.Source)
   .ToDictionary(g => g.Key, g => g.Select(x => x.Target));

现在每个不同的源字符串都映射到IEnumerable<string>个目标。

foreach (var kv in lookup)
    Console.WriteLine("{0} has destinations {1}"
        , kv.Key
        , string.Join(",", lookup[kv.Key]));

修改:以下是演示:http://ideone.com/b18H7X

答案 1 :(得分:0)

您可以使用Zip和ToLookup:

var nameLookup = sourceNames
  .Zip(targetNames, (x, y) => new { Source = x, Target = y })
  .ToLookup(x => x.Source, x => x.Target);