How to Merge Two Lists Using Linq

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:

  1. Method chain:

    var joined = customers1.Union(customers2);
  2. 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:

  1. Group by IdALuno and sum all Nota.
  2. 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



Leave a reply



Submit