1

我有一个对象列表,可以说是用户。

public class User
{
public string Name {get;set;}
public string Sex {get;set;}
public DateTime Birthday {get;set;}
public string Type {get;set;}
public string SubType {get;set;}
public int FilterId {get;set;}
}

可以说我有以下结果

Josh, M, 5/1/1980, Admin, Main, null
John, M, 5/1/1980, User, Main, null
Jane, F, 5/2/1980, User, Main, null
Josh, M, 5/1/1980, Admin, Main 1
John, M, 5/1/1980, User, Main, null
Josh, M, 5/1/1980, User, Main, null

我想得到以下结果。

Josh, M, 5/1/1980, Admin, Main 1
John, M, 5/1/1980, User, Main, null
Jane, F, 5/2/1980, User, Main, null
Josh, M, 5/1/1980, User, Main, null

重要的部分是它返回 Josh 的记录,其中 FilterId 不为空。我认为类似于 Group By 与 Order By 和 firstordefault。

我在编写包含多个字段的 groupby 子句并使其正常工作时遇到问题。

修改了示例以反映需要成为 groupby 一部分的其他属性。

4

4 回答 4

3

您的“FilterId”永远不能为空,因为它是一个int. 假设它实际上是int?aka Nullable<int>,这将起作用:

IEnumerable<User> users = GetSomeUsers() ;
User[] distinctUsers = users
                       .GroupBy( x => new Tuple<string,string,DateTime>(x.Name,x.Sex,x.Birthday))
                       .SelectMany( g => g.OrderBy( x=> x.FilterId.HasValue ? 0 : 1 )
                                          .ThenBy( x => x.FilterId )
                                          .Take(1)
                       )
                       .ToArray()
                            ;

这段代码

  • 姓名、性别和出生日期分组
  • 对过滤器 id 上的每个组进行排序,以便首先整理非空值,然后是空值
  • 取每个组的第一个元素(组中总是至少有一个元素)。
  • 将其展平为一个列表
  • 把它变成一个数组。
于 2013-09-13T19:35:16.323 回答
1

groupby 部分:

.GroupBy(x => new { x.Name , x.Sex, x.Birthday});

并从这里选择第一个:

.GroupBy(x => new { x.Name , x.Sex, x.Birthday}).Select(y=>x.First());

如果您希望第一个不为空,您可以执行 OrderByDescending

.OrderByDescending(usr=>usr.FilterId ).GroupBy(x => new { x.Name , x.Sex, x.Birthday}).Select(y=>y.First()).ToList();

filterId 是一个整数。它不能为空

于 2013-09-13T18:32:21.447 回答
0

对多个属性进行分组的最简单方法是使用匿名类型:

var groups = users.GroupBy(user => new
    {
        Name,
        Type,
        SubType,
    });

这是因为匿名类型的实现是这样的:它们覆盖了Equals比较该类型每个成员的值的方法,并且还覆盖了该GetHashCode方法以使其成为对象所有值的哈希值的复合哈希值。如果您刚刚创建了一个新的命名类型,您将需要自己处理所有这些,这简直是乏味的。

于 2013-09-13T18:31:48.657 回答
-1

主要理解是使用 IEqualityComparer,类 LambdaCustomComparer 是动态使用 LINQ 的助手。

你需要复制和粘贴这个:


public class User
{
    public string Name { get; set; }
    public string Sex { get; set; }
    public DateTime Birthday { get; set; }
    public int? FilterId { get; set; }
}

public class LambdaCustomComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> lambdaComparer;
    private readonly Func<T, int> lambdaHash;

    public LambdaCustomComparer(Func<T, T, bool> lambdaComparer, bool ignoreHashcode = true)
    {
        if (lambdaComparer == null)
            throw new ArgumentNullException("lambdaComparer");

        this.lambdaComparer = lambdaComparer;
        if (ignoreHashcode)
            lambdaHash = obj => 0;
        else
            lambdaHash = EqualityComparer<T>.Default.GetHashCode;
    }

    public LambdaCustomComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
    {
        if (lambdaComparer == null)
            throw new ArgumentNullException("lambdaComparer");
        if (lambdaHash == null)
            throw new ArgumentNullException("lambdaHash");

        this.lambdaComparer = lambdaComparer;
        this.lambdaHash = lambdaHash;
    }

    public bool Equals(T x, T y)
    {
        return lambdaComparer(x, y);
    }

    public int GetHashCode(T obj)
    {
        return lambdaHash(obj);
    }
}

var list = new List<User>
{
    new User() {Name = "Josh", Sex= "M", Birthday = DateTime.Now, FilterId = null},
    new User() {Name = "John", Sex= "M", Birthday = DateTime.Now, FilterId = null},
    new User() {Name = "Jane", Sex= "F", Birthday = DateTime.Now, FilterId = null},
    new User() {Name = "Josh", Sex= "M", Birthday = DateTime.Now, FilterId = 1},
    new User() {Name = "John", Sex= "M", Birthday = DateTime.Now, FilterId = null},
};

var comparer = new LambdaCustomComparer<User>((a, b) => a.Name == b.Name && a.Birthday.Date == b.Birthday.Date && a.Sex == b.Sex && a.FilterId == b.FilterId);

var distinctList = list.GroupBy(user => user, comparer).ToDictionary(a => a.Key, b => b.ToArray());
于 2013-09-13T18:59:20.703 回答