Reputation: 33
I need to merge 2 lists of objects, they share the same interface, but different concrete class.
The result should contain a List of new Objects based on each concrete class, and set a property on each object based on a comparison of the same objects from the lists.
class Program
{
static void Main(string[] args)
{
List<IStuff> stuffList1 = new List<IStuff>();
List<IStuff> stuffList2 = new List<IStuff>();
stuffList1.Add(new Toaster
{
ValueOfMyThing = 1
});
stuffList1.Add(new Car
{
ValueOfMyThing = 3
});
stuffList1.Add(new Onion
{
ValueOfMyThing = 3
});
stuffList2.Add(new Toaster
{
ValueOfMyThing = 2
});
stuffList2.Add(new Car
{
ValueOfMyThing = 1
});
stuffList2.Add(new Onion
{
ValueOfMyThing = 5
});
List<IStuff> stuffList3 = new List<IStuff>();
// Need to merge stuffList1 and stuffList2 taking the stuff that has the higher valueOfMyThing
// The result should be a stuffList3 with a Toaster 2 a Car 3 and an Onion 5
}
}
interface IStuff
{
int ValueOfMyThing { get; set; }
}
class Toaster: IStuff
{
public int ValueOfMyThing { get; set; }
}
class Car : IStuff
{
public int ValueOfMyThing { get; set; }
}
class Onion : IStuff
{
public int ValueOfMyThing { get; set; }
}
Upvotes: 0
Views: 716
Reputation: 460158
First you need the common property in the interface, otherwise you can't use polymoprhism to access it when you enumerate the items in the List<IStuff>
:
interface IStuff
{
int ValueOfMyThing { get; set; }
}
Now add this property to the classes as well (omitted).
Then you could use this LINQ query to group by the concrete type, for example Car
, and get the item with the highest ValueOfMyThing
for each group:
List<IStuff> stuffList3 = stuffList1.Concat(stuffList2)
.GroupBy(x => x.GetType())
.Select(g => g.OrderByDescending(x => x.ValueOfMyThing).First())
.ToList();
This works, but I need stuffList3 to contain new Instances
Then you could provide a method to copy existing instances to new:
public interface IStuff
{
int ValueOfMyThing { get; set; }
IStuff Copy();
}
add it to your classes:
public class Toaster : IStuff
{
public int ValueOfMyThing { get; set; }
public IStuff Copy()
{
return new Toaster { ValueOfMyThing = ValueOfMyThing };
}
}
// ...
and call Copy
:
List<IStuff> stuffList3 = stuffList1.Concat(stuffList2)
.GroupBy(x => x.GetType())
.Select(g => g.OrderByDescending(x => x.ValueOfMyThing).First().Copy())
.ToList();
Upvotes: 4
Reputation: 33
I needed to create new instance of the objects. So I ended up doing this: First as mentioned by Tim Schmelmer:
interface IStuff
{
int ValueOfMyThing { get; set; }
}
class Toaster: IStuff
{
public int ValueOfMyThing { get; set; }
}
class Car : IStuff
{
public int ValueOfMyThing { get; set; }
}
class Onion : IStuff
{
public int ValueOfMyThing { get; set; }
}
Then based on this answer Merge two Lists of different types
List<IStuff> stuffList3 = new List<IStuff>();
var joinedData = stuffList1.Join(stuffList2, sl1 => sl1.GetType(), sl2 => sl2.GetType(), (sl1, sl2) => new { sl1, sl2 });
foreach (var pair in joinedData)
{
var newStuffValue = Math.Max(pair.sl1.ValueOfMyThing, pair.sl2.ValueOfMyThing);
var newStuff = (IStuff)Activator.CreateInstance(pair.sl1.GetType());
newStuff.ValueOfMyThing = newStuffValue;
stuffList3.Add(newStuff);
}
Now I´ve got a list of new concrete classes, but I´m not sure this is the best approach
Upvotes: 0
Reputation: 46229
Frist, you need to let valueOfMyThing
property or field in IStuff
interface be a contract for classes.
interface IStuff
{
int valueOfMyThing { get; set; }
}
class Toaster : IStuff
{
public int valueOfMyThing { get; set; }
}
class Car : IStuff
{
public int valueOfMyThing { get; set; }
}
class Onion : IStuff
{
public int valueOfMyThing { get; set; }
}
Then add this extension method to allow a Distinct Query with lambda parameters:
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this
IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
var seenKeys = new HashSet<TKey>();
foreach (var element in source)
{
if (keySelector != null && seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
And finally use it on your list.
List<IStuff> stuffList3 = new List<IStuff>();
stuffList3.AddRange(stuffList2);
stuffList3.AddRange(stuffList1);
var r = stuffList3.DistinctBy(x => x.valueOfMyThing);
Upvotes: 0