2013-01-15 68 views
1

有没有办法重写下面的GetTransformedCollection方法,以便它使用Linq语句而不是表达式?我目前正试图解决“带有语句正文的lambda表达式不能转换为表达式树”的错误。将Lambda转换为嵌套for循环的Linq语句

public class Obj1 
{ 
    public int Id { get; set; } 
    public string[] Names { get; set; } 
    public string[] Tags { get; set; } 
} 

public class EntCollections 
{ 
    private List<Obj1> _results; 

    [SetUp] 
    public void SetUp() 
    { 
     _results = new List<Obj1> 
     { 
      new Obj1 {Id = 1, Names = new[] {"n1"}, Tags = new[] {"abc", "def"}}, 
      new Obj1 {Id = 2, Names = new[] {"n2", "n3"}, Tags = new[] {"ghi"}}, 
      new Obj1 {Id = 3, Names = new[] {"n1", "n3"}, Tags = new[] {"def", "xyz"}} 
     }; 
    } 

    private static Dictionary<string, List<string>> 
     GetTransformedCollection(IEnumerable<Obj1> results) 
    { 
     var list = new Dictionary<string, List<string>>(); 

     foreach (var result in results) 
     { 
      foreach (var id in result.Names) 
      { 
       if (list.ContainsKey(id)) 
       { 
        list[id].AddRange(result.Tags); 
       } 
       else 
       { 
        list.Add(id, result.Tags.ToList()); 
       } 
      } 
     } 

     return list; 
    } 

    [Test] 
    public void Test() 
    { 
     var list = GetTransformedCollection(_results); 

     Assert.That(list["n1"], Is.EquivalentTo(new [] { "abc", "def", "def", "xyz" })); 
     Assert.That(list["n2"], Is.EquivalentTo(new [] { "ghi" })); 
     Assert.That(list["n3"], Is.EquivalentTo(new [] { "ghi", "def", "xyz" })); 
    } 

P.S我不是太担心的结果类型是一个解释,那只是表达它的返回类型的simplist方式。

+0

你的意思是用Linq替换foreach? –

+0

是................ – Nick

+0

尝试使用Linq All()或ForEach()扩展。 –

回答

2

的想法是找到导致字典中的所有键,然后找到相应的值原始序列Obj1

var distinctNames = results.SelectMany(val => val.Names).Distinct(); 

return distinctNames 
     .ToDictionary(name => name, 
        name => results 
          .Where(res => res.Names.Contains(name)) 
          .SelectMany(res => res.Tags) 
          .ToList()); 
+0

说实话,我发现这个更容易图片的机制,谢谢。 – Nick

7

我会亲自使用ILookup,这是一个不错的选择,只要你有一个Dictionary<T1, List<T2>>,并建有ToLookup()

// Flatten the objects (lazily) to create a sequence of valid name/tag pairs 
var pairs = from result in results 
      from name in result.Names 
      from tag in result.Tags 
      select new { name, tag }; 

// Build a lookup from name to all tags with that name 
var lookup = pairs.ToLookup(pair => pair.name, pair => pair.tag); 
+0

+1。更清洁的解决方案,比使用扩展方法的语法 –

+0

感谢您的ILookup提示! – Nick

+0

我来这个方法,因为它只列举一次。有没有办法在列表中执行“外连接”?通过这个,我的意思是如果一个元素存在于_n_ Names的原始列表中,但是_0_标签,那么这些单独的名称仍然会作为一对空字符串出现在结果集中?我附加了这样一个元素的原始列表,并添加了一个额外的断言。 – Nick