Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如果某些属性匹配,则从列表中删除重复项,并根据某些顺序获取顶部项_C#_Linq_List - Fatal编程技术网

C# 如果某些属性匹配,则从列表中删除重复项,并根据某些顺序获取顶部项

C# 如果某些属性匹配,则从列表中删除重复项,并根据某些顺序获取顶部项,c#,linq,list,C#,Linq,List,我有一个对象列表,比如说用户 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/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

重要的一点是,它返回FilterId不为null的Josh记录。我觉得有点像一个带有orderby和firstordefault的Group By

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


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

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

var groups = users.GroupBy(user => new
    {
        Name,
        Type,
        SubType,
    });
这是因为匿名类型的实现是这样的:它们重写
Equals
方法来比较类型的每个成员的值,还重写
GetHashCode
方法,使其成为对象所有值的散列的复合散列。如果您刚刚创建了一个新的命名类型,那么您需要自己处理所有这些,这非常繁琐。

groupby部分:

.GroupBy(x => new { x.Name , x.Sex, x.Birthday});
从这里选择第一个:

.GroupBy(x => new { x.Name , x.Sex, x.Birthday}).Select(y=>x.First());
如果希望第一个值不为null,可以执行OrderByDescending

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

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

主要的理解是使用IEqualityComparer,类LambdaCustomComparer是使用LINQ动态执行此操作的帮助器

您需要复制并粘贴以下内容:


公共类用户
{
公共字符串名称{get;set;}
公共字符串Sex{get;set;}
公共日期时间生日{get;set;}
公共int?FilterId{get;set;}
}
公共类LambdaCustomComparer:IEqualityComparer
{
私有只读Func lambdaComparer;
私有只读Func lambdaHash;
公共LambdaCustomComparer(Func lambdaComparer,bool ignoreHashcode=true)
{
if(lambdaComparer==null)
抛出新ArgumentNullException(“lambdaComparer”);
this.lambdaComparer=lambdaComparer;
if(ignoreHashcode)
lambdaHash=obj=>0;
其他的
lambdaHash=EqualityComparer.Default.GetHashCode;
}
公共LambdaCustomComparer(Func lambdaComparer,Func lambdaHash)
{
if(lambdaComparer==null)
抛出新ArgumentNullException(“lambdaComparer”);
if(lambdaHash==null)
抛出新的ArgumentNullException(“lambdaHash”);
this.lambdaComparer=lambdaComparer;
this.lambdaHash=lambdaHash;
}
公共布尔等于(TX,TY)
{
返回lambdaComparer(x,y);
}
公共int GetHashCode(T obj)
{
返回lambdaHash(obj);
}
}
变量列表=新列表
{
新用户(){Name=“Josh”,Sex=“M”,生日=日期时间。现在,FilterId=null},
新用户(){Name=“John”,Sex=“M”,生日=日期时间。现在,FilterId=null},
新用户(){Name=“Jane”,Sex=“F”,生日=日期时间。现在,FilterId=null},
新用户(){Name=“Josh”,Sex=“M”,生日=日期时间。现在,FilterId=1},
新用户(){Name=“John”,Sex=“M”,生日=日期时间。现在,FilterId=null},
};
var comparer=new LambdaCustomComparer((a,b)=>a.Name==b.Name&&a.birth.Date==b.birth.Date&&a.Sex==b.Sex&&a.FilterId==b.FilterId);
var distinctList=list.GroupBy(user=>user,comparer).ToDictionary(a=>a.Key,b=>b.ToArray());

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

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()
                            ;
IEnumerable users=GetSomeUsers();
用户[]distinctUsers=用户
.GroupBy(x=>新元组(x.Name,x.Sex,x.birth))
.SelectMany(g=>g.OrderBy(x=>x.FilterId.HasValue?0:1)
.ThenBy(x=>x.FilterId)
.采取(1)
)
.ToArray()
;
此代码

  • 姓名、性别和出生日期分组
  • 对筛选器id上的每个组进行排序,以便先整理非空值,然后整理空值
  • 获取每个组的第一个元素(组中始终至少有一个元素)
  • 将其展平为单个列表
  • 将其转换为数组

“我觉得有点像一个带有Order By和firstordefault的Group By。”太好了。这听起来确实是一个很有希望的想法。你用这个想法想出了什么样的实现方案?向我们展示它们是什么,并解释为什么(具体地说)它们不起作用。好的,那么你把想法写进代码了吗?结果如何?对不起,我应该提供更多的细节。我很难为此编写GroupBy()子句。@GroupBy很容易。这部分就是
.GroupBy(user=>user.Name)
。这就是全部。从这里开始,您需要使用给定的条件将每个组投影到单个项目中。@Servy我添加了额外的groupby列,以更准确地表示我的需要。我真的需要按名称、类型和子类型分组。这不起作用。您的分组依据将基于
用户
对象的标识进行分组,而不是基于对象的值,除非您提供了自定义的
IEqualityComparer
,定义该类型的值相等。@Servy修复并测试了它您更改了三种解决方案之一。两个仍然是错误的。这没有正确地对这些类型的值进行散列(它只是使用默认实现,而不是使用值语义),因此,
GroupBy
不起作用。它不起作用,因为它将使用
User
的默认
GetHashCode
实现,它不会覆盖
对象
的实现,该对象基于对象的引用创建哈希,而您的目标是基于该对象中的几个值创建哈希代码。我理解您的观点
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()
                            ;