Linq在其他列表中找到列表的第一个值

时间:2012-12-19 20:45:49

标签: .net linq list lambda

一个看似简单的问题: 我有一个字符串列表(从属性文件中读取):

IList<string> defaultValues = new List<string> {"0458","0309"};

和一些对象的列表,每个对象都具有string类型的属性:

IList<Token> tokens = new List<Token>
{
    new Token {DisplayValue = "0123"},
    new Token {DisplayValue = "0309"},
    new Token {DisplayValue = "0203"},
    new Token {DisplayValue = "0458"},
    new Token {DisplayValue = "0911"}
};

public class Token
{
   public string DisplayValue { get; set; }
}

现在我想得到令牌元素,其中DisplayValue匹配defaultValues(0485)的第一个元素。如果未找到具有DisplayValue 0485的元素,则defaultvalues中的第二个元素应匹配(0309),依此类推。

defaultValues List可以是动态的,因此可以添加更多值,并且始终第一个条目应具有优先级。

因此defaultValues列表是字符串的优先级列表,索引越低,优先级越高。 在上面的示例中,结果应为“0458”。

我可以这样做:

string result = string.Empty;

foreach (var searchValue in defaultValues)
{
    if (tokens.Any(token => token.DisplayValue == searchValue))
    {
        result = searchValue;
    }   
}

但是我觉得这样的事情可以更优雅地完成而且没有预告......

2 个答案:

答案 0 :(得分:2)

在这种情况下,使用Any是O(n ^ 2),这可能不是最高效的。执行此操作的最佳方法可能是执行GroupJoin(将其改为O(n)),然后选择匹配的第一个令牌。请记住,GroupJoin仅在完全匹配的键上执行此操作,因此,如果您要查找比较或子字符串搜索,则必须找到其他方法。

defaultValues
    .GroupJoin(
        tokens, // matching 0:n tokens per default value
        defVals => defVals, // key selector for our left source
        tks => tks.DisplayValue, // key selector for our right source
        (defVal, tks) => tks.FirstOrDefault()) // result selector for our matches
    .FirstOrDefault(match => match != null)

这样做的好处是只遍历每个集合一次,并将所有令牌与相应的DefaultValue匹配(因此每个默认值可以有多个匹配)。您可能会defaultValues.FirstOrDefault(x => tokens.Any(t => t == x)),但您遇到了同样的问题(可能存在O(n ^ 2)复杂度)。从这里开始,您可以检查它是否为空(使用空合并)并在令牌中添加一个名为Empty的静态常量,初始化为new Token { DisplayValue = string.Empty }。之后你可以这样做:

(defaultValues
    .GroupJoin(
        ...
    .FirstOrDefault(match => match != null) ?? Token.Empty).DisplayValue

答案 1 :(得分:0)

基本上,您需要从Linq / Lambada 结果中查找投影。

我会尝试这样的事情:

var macthes = tokens.Any(t => t.DisplayValue.In(defaultValues))
              .Select(y =>y.DisplayValue);