2012-10-24 31 views
2

我有成对字符串的列表(等长),称之为“源”和“目标”。一个来源可能映射到多个目标。我可以使用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做到这一点?

回答

0

您可以使用Zip和ToLookup:

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

这是非常简洁,感谢介绍我到返回的ToLookup扩展方法'查找'。还有一件事:我怎样才能从这个只列出唯一键的列表中提取一个'List '对象?我有一种感觉,一个简单的'ToList()'不会这样做。 –

+0

我很愚蠢,我只需要'targetNames.Distinct()。ToList()'! –

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

相关问题