使用Linq的GroupBy方法,将每个空值作为一个分组

12

我有一个带有可空整数属性"GroupId"的对象。

对于这个对象的列表,我想按照"GroupId"进行分组。但是如果我这样做,所有的空值将会形成一组。

例子:

对象1:GroupId:NULL

对象2:GroupId:NULL

对象3:GroupId:1

对象4:GroupId:1

对象5:GroupId:2

对象6:GroupId:2

MyList.GroupBy(f => f.GroupId, key => new {Object = key});

我会得到3组。

我怎样才能得到4组呢?每个 NULL 值都分配一个组...


(过滤非空值后,按 GroupId 分组)并集(过滤空值后,按主键应用分组)。 - Jenish Rabadiya
@JenishRabadiya 注意,GroupBy 会保持元素/组的顺序,而你的解决方案会破坏顺序。 - xanatos
@xanatos 嗯...你是正确的。 - Jenish Rabadiya
2个回答

11

这可能是最短的解决方案:

var grouped = MyList.GroupBy(f => f.GroupId != null ? (object)f.GroupId : new object(), key => new { Object = key });

请注意,分组的“键”将是object类型。对于null元素,我创建一个新的“空”object。对象的相等比较器将使它们全部不同。对于非空数字,我只需将它们装箱为对象。装箱的整数保持相等运算符。所以:

new object().Equals(new object()) == false // always

and
((object)1).Equals((object)1) == true // always

((object)1).Equals((object)2) == false // always

更正确的解决方案是实现一个IEqualityComparer<int?>

public class MyComparer : IEqualityComparer<int?> {
    public bool Equals(int? x, int? y) {
        if (x == null || y == null) {
            return false;
        }

        return x.Value == y.Value;
    }

    public int GetHashCode(int? obj) {
        return obj.GetHashCode(); // Works even if obj is null :-)
    }
}

并使用它:

var grouped2 = MyList.GroupBy(f => f.GroupId, key => new { Object = key }, new MyComparer());

2
(object)1 == (object)1 总是为假。(object) == (object) 是引用相等性,它不会调用 object.Equals - user4003407
它的运行很好,但列表作为匿名列表出现,有没有办法将列表作为我们的模型或实体类型对象提取? - Md Aslam
@MdAslam 如果你正在使用EF/EF Core,那就是另一个问题了... - xanatos

4

通用比较器,可无需装箱即可使用。

public class NullableComparer<T> : IEqualityComparer<T?>
        where T : struct
{
    public bool Equals(T? x, T? y)
    {
        if (x == null || y == null)
        {
            return false;
        }

        return x.Equals(y);
    }

    public int GetHashCode(T? obj)
    {
        return obj.GetHashCode();
    }
}

你可以这样使用它:
// where GroupId as a nullable Guid 
var grouped = MyList.GroupBy(f => f.GroupId, new NullableComparer<Guid>());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接