I am trying to merge two lists into one List without duplicates
JOIN operator returns only common elements
These are lists in JSON
List1 is:
{
"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
}
List2 is:
{
"screenID": 96,
"create": true,
"read": true,
"update": true,
"delete": true,
"print": false
},
{
"screenID": 97,
"create": true,
"read": true,
"update": true,
"delete": true,
"print": false
}
If ScreenID is same then I want to compare between CRUD elements like:
if(ScreenID == 96){
Create = List1.Create == true && List2.Create == false ? true : false
}
I tried this : var finalList = list1.Union(list2);
but the result was:
{
"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,
I am beginner in LINQ so any help is appreciated
EDIT I am using .NET 3.1
EDIT: I've made some changes to adapt my original answer to .Net 3.5, this should now work provided you're working with C# 7.3 or later (Set by <LangVersion>7.3</LangVersion>
in your .csproj file). I ditched the HashSet<T>
for a Dictionary<T>
which actually made the whole thing less verbose.
While the exising answer is good I'd like to add an alternate approach using an extension method that essentially should do the same as UnionBy
but accept an additonal Func<T, T, T>
for handling duplicates.
The UnionComparer
makes it a bit verbose but that essentially just wraps the IEqualityComparer<TKey>
for the key selector.
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;
}
I've made a simple example class for your data:
class Operation
{
public int ScreenId { get; set; }
public bool Create { get; set; }
}
Usage:
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();
EDIT: I just saw you are limited to .Net 3.5, I'm not entirely sure you will not have to make any changes to this but HashSet<T>
and IEqualityComparer<T>
should be supported