.net LINQ联合两个ID相同但类型不同的列表

6jygbczu  于 2022-12-14  发布在  .NET
关注(0)|答案(3)|浏览(142)

我正在尝试将两个列表合并为一个没有重复项的列表
JOIN运算符仅返回公共元素
这些是JSON格式的列表
列表1为:

{
    "screenID": 96,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": true
},
{
    "screenID": 97,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": true
},
{
    "screenID": 98,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": true
}

列表2为:

{
    "screenID": 96,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": false
},
{
    "screenID": 97,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": false
}

如果ScreenID相同,则我希望在CRUD元素之间进行比较,如下所示:

if(ScreenID == 96){
Create = List1.Create == true && List2.Create == false ? true : false
}

我试过这个:变量finalList =列表1.联合(列表2);
但结果是

{
    "screenID": 96,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": true
},
{
    "screenID": 97,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": true
},
{
    "screenID": 98,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": true
},
{
    "screenID": 96,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,
    "print": false
},
{
    "screenID": 97,
    "create": true,
    "read": true,
    "update": true,
    "delete": true,

我是LINQ的初学者,所以任何帮助都很感激

编辑我使用的是.NET 3.1

8nuwlpux

8nuwlpux1#

**编辑:**我做了一些修改,使我原来的答案适应.Net 3.5,如果你使用C# 7.3或更高版本,现在应该可以工作了(在你的.csproj文件中由<LangVersion>7.3</LangVersion>设置)。我放弃了HashSet<T>,改为Dictionary<T>,这实际上使整个事情变得不那么冗长。

虽然现有的答案是好的,但我想添加一个替代方法,使用扩展方法,本质上应该做与UnionBy相同的事情,但接受一个额外的Func<T, T, T>来处理重复。
UnionComparer使它有点冗长,但这实际上只是为键选择器 Package 了IEqualityComparer<TKey>

public static IEnumerable<T> UnionBy<T, TKey>(
    this IEnumerable<T> first,
    IEnumerable<T> second,
    Func<T, TKey> keySelector,
    Func<T, T, T> duplicateHandler,
    IEqualityComparer<TKey> keyComparer = null)
{
    if(keyComparer is null)
        keyComparer = EqualityComparer<TKey>.Default;

    var result = new Dictionary<TKey, T>(keyComparer);

    foreach (var item in first)
        result.Add(keySelector(item), item);

    foreach (var item in second)
    {
        var key = keySelector(item);
        if (result.TryGetValue(key, out var duplicate))
        {
            result[key] = duplicateHandler(item, duplicate);
        }
        else
        {
            result.Add(key, item);
        }
    }
    return result.Values;
}

我为您的数据创建了一个简单的示例类:

class Operation
{
    public int ScreenId { get; set; }
    public bool Create { get; set; }
}

用法:

var first = new List<Operation>()
{
    new Operation () { ScreenId = 1, Create = false },
    new Operation () { ScreenId = 2, Create = false },
    new Operation () { ScreenId = 3, Create = false },
};
            var second = new List<Operation>()
{
    new Operation () { ScreenId = 3, Create = true },
    new Operation () { ScreenId = 4, Create = true },
    new Operation () { ScreenId = 5, Create = true },
};

var result = first.UnionBy(
    second,
    o => o.ScreenId,
    (a, b) => new Operation { ScreenId = a.ScreenId, Create = a.Create || b.Create });

foreach (var operation in result)
    Console.WriteLine($"ID: {operation.ScreenId}, Create: {operation.Create}");

Console.ReadLine();

**编辑:**我刚才看到您只能使用.Net 3.5,我不确定您是否需要对此进行任何更改,但应该支持HashSet<T>IEqualityComparer<T>

3npbholx

3npbholx2#

.NET 6引入了UnionBy,可用于基于表达式合并两个集合。当发现重复项时,该方法返回遇到的第一个项。应首先对这两个集合进行排序,以控制返回哪个项:

var ordA=colA.OrderByDescending(x=>new {x.ScreenId,x.Create,x.Update,x.Delete});
var ordB=colB.OrderByDescending(x=>new {x.ScreenId,x.Create,x.Update,x.Delete});

var unioned=ordA.UnionBy(ordB,x=>x.ScreenId);

对于更复杂的逻辑,应修改顺序表达式以确保所需的项位于第一位。例如,要选择具有最多标志的项,可使用Enumerable.Count(t=>t)

var ordA=colA.OrderByDescending(x=>new {
    x.ScreenId,
    Count=new[]{ x.Create,x.Update,x.Delete }
              .Count(t=>t)
});

使用区分方式

在以前的版本中,.NET版本可以使用MoreLINQ库。没有UnionBy,但是DistinctBy可以在连接后用于相同的作业。同样,顺序控制返回的内容:

var all=colA.Concat(colB);

var unioned=all.OrderByDescending(x=>new { x.ScreenId,x.Create,x.Update,x.Delete})
               .DistinctBy(x=>x.ScreenId);

DistinctBy在.NET 6中也可用。

ffx8fchx

ffx8fchx3#

有阶级

public class Screen
    {
        public int screenID { get; set; }
        public bool create { get; set; }
        public bool read { get; set; }
        public bool update { get; set; }
        public bool delete { get; set; }
        public bool print { get; set; }
    }

这个简单的联合工作:

var result = list.Union(list2)
        .GroupBy(x => x.screenID)
        .Select(x => new 
        {
            screenID = x.Key,
            create = x.Any(y => y.create),
            read = x.Any(y => y.read),
            update = x.Any(y => y.update),
            delete = x.Any(y => y.delete),
            print = x.Any(y => y.print)
        });

相关问题