合并可能为空的 LINQ 查询结果

本文关键字:LINQ 查询 结果 合并 | 更新日期: 2023-09-27 18:35:41

我使用 Linq 从 4 个级联下拉菜单返回 ID。

用户可能已从 1 个或所有菜单中选择了 1 个或多个值。 然后,从用户选择中,我查询数据表的文本列以获取代表性 ID。

如果用户从第 4 个(也是最低级别)下拉列表中选择,那么他们将从上述所有下拉列表中选择。

如果用户从菜单 1 中选择"X",

从菜单 2 中选择"Y",而在其他菜单中没有任何内容,我希望看到results1,比如 10 行,其中"X"存在于 [Col_1] 中,然后向下查询到results2 5 行,其中"Y"存在于 [Col_2]。

编辑守则(基本形式)

var results1 = 
    from a in dt.AsEnumerable()
    where stringArray1.Contains([Col1])
    select a;

var results2 = 
    from a in results1
    where stringArray2.Contains([Col2])
    select a;
var results3 = 
    from a in results2
    where stringArray3.Contains([Col3])
    select a;
var results4 = 
    from a in results3
    where stringArray4.Contains([Col4])
    select a;
var results = results4 ?? results3 ?? results2 ?? results1;

results4取决于results3的结果,results3取决于results2results2取决于results1

可能是results4 - 2是空的,因此我想知道我是否可以将它们合并成一个最终变量,例如:

var results = results4 ?? results3 ?? results2 ?? results1;

这是抛出错误:

Operator '??' cannot be applied to operands of type 'System.Collections.Generic.IEnumerable<AnonymousType#4>'

有没有人有任何狡猾的想法如何解决这个问题? 我尽量不写很长的代码,处理每一个可能的结果。

提前谢谢大家(希望这个问题有意义!

厘米

合并可能为空的 LINQ 查询结果

因此,根据您使用的查询,任何结果都不会null。 其中一些可能是空的,但它们不会null。 这意味着??运算符永远不会做任何有用的事情。

您希望它如何表现? 你想说,"如果这个结果是空的,使用另一个结果? 为此,请使用我在下面编写的方法。

public static IEnumerable<T> Coalesce<T>(IEnumerable<T> first, IEnumerable<T> second)
{
  if(first == null || !first.Any())
  {
    return second;
  }
  else
  {
    return first;
  }
}

然后,这可以用作:

Coalesce(results4, Coalesce(results3, Coalesce(results2, results1)));

这样做的结果是,"返回result4,除非它是空的。 如果是空返回results3 . 如果results3为空,则返回results2,如果results2为空,则返回results1

如果您认为使用它足够多,可以将其设置为扩展方法。 它会让它更漂亮,但也会使所有其他IEnumerable的智能感觉变得混乱,所以它可能不值得。

如果你不想写冗长的代码,你可以这样做

public static IEnumerable<T> SomeOrAll<T>(
    this IEnumerable<T> source, 
    Predicate<T> where)
{
    var results = source.Where(where)
    return results.Any() ? results : source;
}
var results = dt.AsEnumerable()
    .SomeOrAll(a => a.stringArray4.Contains([Col4]))
    .SomeOrAll(a => a.stringArray3.Contains([Col3]))
    .SomeOrAll(a => a.stringArray2.Contains([Col2]))
    .SomeOrAll(a => a.stringArray1.Contains([Col1]));

但是,我怀疑,如果你退后一步,你可以做别的事情。如果人们经常需要这个扩展,它已经存在(也许)。

我会重写查询来解决问题,而不是在事后处理它。

public List<string> FilterResults(string first, string second, string third, string fourth)
{
    var query = from a in dt.AsEnumerable()
                let firsts = first != null ? a.Where( x => x.stringArray1.Contains( first ) ) : null,
                let seconds = second != null ? firsts.Where( x => x.stringArray2.Contains( second ) ) : null,
                let thirds = third != null ? seconds.Where( x => x.stringArray3.Contains( third ) ) : null,
                let fourths = fourth != null ? thirds.Where( x => x.stringArray4.Contains( fourth ) ) : null
                select fourths ?? thirds ?? seconds ?? firsts;
    return query.ToList();
}

我没有运行这个虽然 VS,但总体想法应该会遇到。