1

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

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

和一些对象的另一个列表,每个对象都有一个字符串类型的属性:

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 的元素,则默认值中的第二个元素应匹配 (0309),依此类推。

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

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

我可以做这样的事情:

string result = string.Empty;

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

但我认为这样的事情可以更优雅地完成并且没有 foreach ......

4

2 回答 2

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))。从这里,您可以检查它是否为 null(使用 null 合并)并添加一个Empty在 Token 中调用的静态常量,该常量初始化为new Token { DisplayValue = string.Empty }. 之后你可以这样做:

(defaultValues
    .GroupJoin(
        ...
    .FirstOrDefault(match => match != null) ?? Token.Empty).DisplayValue
于 2012-12-19T21:37:17.617 回答
0

基本上你需要从你的 Linq/Lambada结果中寻找一个投影。

我会尝试这样的事情:

var macthes = tokens.Any(t => t.DisplayValue.In(defaultValues))
              .Select(y =>y.DisplayValue);
于 2012-12-19T20:52:01.643 回答