代码之家  ›  专栏  ›  技术社区  ›  Brett Bim

选择列表的子集,列表中首先包含特定元素

  •  3
  • Brett Bim  · 技术社区  · 17 年前

    我在C#中列出了所有具有Name属性的供应商。我希望允许用户通过搜索名称来筛选该列表。筛选器字符串可以是部分匹配或完全匹配。但是,如果生成的列表包含精确匹配,则它应该位于列表中的零位置,并且所有部分匹配都在该位置之后。

    使用linq和lambdas,我可以很容易地获得子列表,但我不得不求助于一种技巧:如果存在精确匹配,则创建第二个列表,添加它,然后添加其余的匹配项,而不添加精确匹配项。感觉不雅。有没有更简单的方法?我的当前代码(从内存中完成,因此可能无法编译):

    List<Vendor> temp = vendors.Where(v => v.Name.ToUpper().Contains(vendorNameSearch)).ToList();
    Vendor exactMatch = vendors.Single(v => v.Name.ToUpper().Equals(vendorNameSearch));
    
    if(null == exactMatch){return temp;}
    else
    {
        List<Vendor> temp1 = new List<Vendor>();
        temp1.Add(exactMatch);
        temp1.AddRange(temp.Remove(exactMatch));
        return temp1;
    }
    
    4 回复  |  直到 17 年前
        1
  •  3
  •   tvanfosson    17 年前

    Levenshtein 距离——对于精确匹配,它应该是零——并按此升序排列结果。通过这种方式,您首先获得精确匹配,其余结果按与搜索字符串的相似性(至少一个度量)排序。

    var list = vendors.Where( v => v.Name.ToUpper().Contains( vendorNameSearch ) )
                      .OrderBy( v => ComputeLevenshtein( v.Name.ToUpper(),
                                                         vendorNameSearch ) );
    

        2
  •  3
  •   Nathan Baulch    17 年前

    否则,您可以使用复合排序实现所需的行为:

    vendors.Where(v => v.Name.ToUpper().Contains(vendorNameSearch))
           .OrderBy(v => !string.Equals(v.Name, vendorNameSearch))
           .ThenBy(v => v.Name)
           .ToList();
    

        3
  •  1
  •   Darrel Miller    17 年前

    我不知道这有多有效,但这里有另一个选择,

    List<String> strings = new List<String> {"Cat","Dog","Pear","Apple","Catalog"};
    
    var results = (from st in strings
        where st == "Cat"
        select new {Priority = 1,st}).Union(
    
        from st in strings
        where st.Contains("Cat")
        select new {Priority = 2, st}).OrderBy(x => x.Priority).Select(x=> x.st).Distinct();
    
        4
  •  1
  •   kevingessner    17 年前

    按字符串长度的绝对差排序。精确匹配将是唯一具有相同长度的匹配(abs.diff.=0),而其他匹配都将大于0:

    var list = vendors.Where(v => v.Name.ToUpper().Contains(vendorNameSearch))
                      .OrderBy(v => Math.Abs(v.Name.ToUpper().Length - vendorNameSearch.Length)));
    

    这将是一个任意的排序,但它实现了您的主要目标。

    但是,当然,像原始代码那样的两步解决方案没有什么错,如果它能做到这一点的话。