Merge two Listobject into one List in Linq
Use Concat
and OrderBy
var result = list1.Concat(list2).OrderBy(x => x.Elevation).ToList();
If you want to remove duplicates and get an unique set of elements you can also use Union
method:
var result = list1.Union(list2).OrderBy(x => x.Elevation).ToList();
In order to make it work properly you need to overide Equals
and GetHashCode
methods in your class.
Join two lists using linq queries - C#
It looks like there is no query equivalent for Union
method. You will need to use this method either in method chain call or in your query.
If you look at MSDN documentation on returning the set union of two sequences, you will see the following official query:
var infoQuery =
(from cust in db.Customers
select cust.Country)
.Union
(from emp in db.Employees
select emp.Country)
;
So, there are only two options in your case:
Method chain:
var joined = customers1.Union(customers2);
LINQ query
var joined = (from c1 in customers1
select c1)
.Union
(from c2 in customers2
select c2);
Can I merge two lists using Linq?
Here is a method that produces the correct output. Is there an easier way to do this? Can this be done with Linq only?
private void DoTest()
{
var packItems = new List<PackItem>()
{
new PackItem() {ID = 4, Quantity = 5, Length = "10"},
new PackItem() {ID = 5, Quantity = 2, Length = "4"},
new PackItem() {ID = 6, Quantity = 1, Length = "4"}
};
var productionInfoList = new List<ProductionInfo>()
{
new ProductionInfo() { CoilNum = "A", Quantity = 4, Length = "10"},
new ProductionInfo() { CoilNum = "B", Quantity = 1, Length = "10"},
new ProductionInfo() { CoilNum = "B", Quantity = 2, Length = "4"},
new ProductionInfo() { CoilNum = "A", Quantity = 1, Length = "4"},
};
//first create a list with one item for each pieces
var individualProduction = new List<ProductionInfo>();
foreach (var item in productionInfoList)
{
for (int i = 0; i < item.Quantity; i++)
{
individualProduction.Add(new ProductionInfo()
{
Quantity = 1,
Length = item.Length,
CoilNum = item.CoilNum
});
}
}
//next loop through and assign all the pack line ids
foreach (var item in individualProduction)
{
var packItem = packItems.FirstOrDefault(i => i.Quantity > 0 && i.Length == item.Length);
if (packItem != null)
{
packItem.Quantity -= 1;
item.LineID = packItem.ID;
}
else
{
item.Quantity = 0;
}
}
//now group them back into a merged list
var grouped = individualProduction.GroupBy(i => (i.CoilNum, i.LineID, i.Length));
//output the merged list
var merged1 = grouped.Select(g => new ProductionInfo()
{
LineID = g.Key.LineID,
CoilNum = g.Key.CoilNum,
Length = g.Key.Length,
Quantity = g.Count()
});
}
Using Linq to combine two lists and get total quantity
(I originally answered this question incorrectly, see the second heading below ("To combine all distinct Tshirt
instances together") for my original, irrelevant, answer)
To combine all Tshirt instances and sum their qtys:
I see you're using a tuple of color + size
to uniquely identify a type of t-shirt, which means if we combine all Tshirt
instances together (Concat
), then group them by color + size
, then Sum
the qty
values, then return new Tshirt
instances in a new list.
List<Tshirt> aggregatedShirts = uniqueShirts = Enumerable
.Empty<Tshirt>()
.Concat( list1 )
.Concat( list2 )
.GroupBy( shirt => new { shirt.Color, shirt.size } )
.Select( grp => new Tshirt()
{
Color = grp.Key.Color,
size = grp.Key.size,
qty = grp.Sum( shirt => shirt.qty )
} )
.ToList();
To combine all distinct Tshirt
instances together
Assuming class Tshirt
implements IEquatable<Tshirt>
then just use Concat( ... ).Distinct().ToList()
:
I'd do it this way, others might prefer not to use Empty
:
List<Tshirt> uniqueShirts = Enumerable
.Empty<Tshirt>()
.Concat( list1 )
.Concat( list2 )
.Distinct()
.ToList();
If Tshirt
does not implement IEquatable
then you can use the overload of Distinct
that accepts an IEqualityComparer<TSource>
:
class TshirtComparer : IEqualityComparer<Tshirt>
{
public static TshirtComparer Instance { get; } = new TshirtComparer();
public Boolean Equals(Tshirt x, Tshirt y)
{
if( ( x == null ) != ( y == null ) ) return false;
if( x == null ) return true;
return x.Color == y.Color && x.size == y.size && x.qty == y.qty;
}
public Int32 GetHashCode(Tshirt value)
{
if( value == null ) return 0;
// See https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
Int32 hash = 17;
hash = hash * 23 + value.Color?.GetHashCode() ?? 0;
hash = hash * 23 + value.size?.GetHashCode() ?? 0;
hash = hash * 23 + value.qty;
return hash;
}
}
Usage:
List<Tshirt> uniqueShirts = Enumerable
.Empty<Tshirt>()
.Concat( list1 )
.Concat( list2 )
.Distinct( TshirtComparer.Instance )
.ToList();
Then to get the total quantity:
Int32 totalQuantity = uniqueShirts.Sum( shirt => shirt.qty );
How to merge two lists using LINQ?
I would strongly recommend against using string-concatenation to represent this information; you will need to perform unnecessary string-manipulation if you want to get the original data back later from the merged list. Additionally, the merged version (as it stands) will become lossy if you ever decide to add additional properties to the class.
Preferably, get rid of the Merge
method and use an appropriate data-structure such as a multimap that can each map a collection of keys to one or more values. The Lookup<TKey, TElement>
class can serve this purpose:
var personsById = list1.Concat(list2)
.ToLookup(person => person.ID);
Anyway, to answer the question as asked, you can concatenate the two sequences, then group persons by their ID
and then aggregate each group into a single person with the provided Merge
method:
var mergedList = list1.Concat(list2)
.GroupBy(person => person.ID)
.Select(group => group.Aggregate(
(merged, next) => merged.Merge(next)))
.ToList();
EDIT: Upon re-reading, just realized that a concatenation is required since there are two lists.
Merge 2 Lists of different types using LinQ
Since List
is expecting strongly-typed data type, thus one of the data type must give in. And in between string
and int
, int
can always be represented as string
but not all string
can be represented as int
(only numeric type under certain range). Thus, int
data type should give in.
Then you could use ToString()
to change the int
data type to string
and combine it with your original List
.
List<string> myCars = new List<String> { "Yugo", "Aztec", "BMW" };
List<int> modeList = new List<int> { 1, 2, 3 };
var carConcat = myCars.Concat(from c2 in modeList select c2.ToString());
Alternatively, you could create List<object>
which encompass all the data types.
Edit:
Note that you could also remove the identity select (from c in myCars select c)
, credited to Aron's comment.
LINQ - How to merge two lists and sum specific field when the ids are matched
You can use System.Linq
to:
- Group by
IdALuno
and sum allNota
. - Order by
IdALuno
.
using System.Linq;
List<Semestre> result = new List<Semestre>();
result.AddRange(semestre1);
result.AddRange(semestre2);
result = result.GroupBy(x => x.IdALuno)
.Select(x => new Semestre
{
IdALuno = x.Key,
Nota = x.Sum(y => y.Nota)
})
.OrderBy(x => x.IdALuno)
.ToList();
Sample program
Combine two lists with linq
myIds.Union(yourIds)
.Select(x => new
{
Id = x,
Mine = myIds.Contains(x),
Yours = yourIds.Contains(x)
});
Related Topics
Where Is My System.Numerics Namespace
Datetime.Adddays() Not Working as Expected
Use Different Name for Serializing and Deserializing with JSON.Net
Nullable Object Must Have a Value
How to Tell Fluent Nhibernate Not to Map a Class Property
Execute Unit Tests Serially (Rather Than in Parallel)
In-Memory Database Doesn't Save Data
Serializable Classes and Dynamic Proxies in Ef - How
Xaml Gridview Itemtemplate Not Binding to Control
Using Ssl and Sslstream for Peer to Peer Authentication
Why Does System.Threading.Timer Stop on Its Own
Get the Object Is Null Using JSON in Wcf Service
Unit Testing That Events Are Raised in C# (In Order)
MVC HTML.Beginform Different Url Schema