2011-05-01 101 views
1

考虑这个简短的片段:如何在LINQ中执行此查询?

var candidateWords = GetScrabblePossibilities(letters); 
var possibleWords = new List<String>(); 

foreach (var word in candidateWords) 
{ 
    if (word.Length == pattern.Length) 
    { 
     bool goodMatch = true; 
     for (int i=0; i < pattern.Length && goodMatch; i++) 
     { 
      var c = pattern[i]; 
      if (c!='_' && word[i]!=c) 
       goodMatch = false; 
     } 
     if (goodMatch) 
      possibleWords.Add(word); 
    } 
} 

是否有使用LINQ干净表达这样一种方式?
这是什么?

回答

3

一个简单的翻译就是使用Zip运算符将每个候选字覆盖在模式字上。

var possibleWords = from word in candidateWords 
        where word.Length == pattern.Length 
         && word.Zip(pattern, (wc, pc) => pc == '_' || wc == pc) 
           .All(match => match) 
        select word; 

如果你真的想专注于指数,你可以使用Range操作:

var possibleWords = from word in candidateWords 
        where word.Length == pattern.Length 
         && Enumerable.Range(0, word.Length) 
            .All(i => pattern[i] == '_' 
              || pattern[i] == word[i]) 
        select word; 

编辑:

正如大卫·尼尔指出,Zip运营商不可用前.NET 4.0。然而,它自己实现它是trivial

+0

记住,'Zip'只会用C#4.0 – 2011-05-01 16:15:53

+0

工作'。所有()'返回一个布尔值,他需要一个列表。 – 2011-05-01 16:23:03

+0

@Paul:它是'where'子句的一部分。要将查询物化为列表,只需调用'ToList()'。 – Ani 2011-05-01 16:25:23

0

这样做W/O拉链的另一种方式:

var possibleWords = candidateWords.Where(w => w.Length == pattern.Length && 
             word.Select((c, i) => pattern[i] == '_' || 
                   pattern[i] == c) 
              .All(b => b)) 
            .ToList();