根据比较合并2个对象列表,没有重复项

时间:2018-10-02 07:48:38

标签: c#

我需要合并2个对象列表,它们共享相同的接口,但具有不同的具体类。

结果应包含一个基于每个具体类的新对象列表,并基于列表中相同对象的比较为每个对象设置属性。

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; }
}

3 个答案:

答案 0 :(得分:4)

首先,您需要接口中的common属性,否则当您枚举List<IStuff>中的项目时,您不能使用多态性来访问它:

interface IStuff
{
    int ValueOfMyThing { get; set; }
}

现在也将此属性添加到类中(省略)。

然后,您可以使用此LINQ查询对具体类型进行分组,例如Car,并为每个组获取最高ValueOfMyThing的项目:

List<IStuff> stuffList3 = stuffList1.Concat(stuffList2)
    .GroupBy(x => x.GetType())
    .Select(g => g.OrderByDescending(x => x.ValueOfMyThing).First())
    .ToList();
  

这可行,但是我需要stuffList3包含新的实例

然后,您可以提供一种将现有实例复制到新实例的方法:

public interface IStuff
{
    int ValueOfMyThing { get; set; }
    IStuff Copy();
}

将其添加到您的班级中:

public class Toaster : IStuff
{
    public int ValueOfMyThing { get; set; }
    public IStuff Copy()
    {
        return new Toaster { ValueOfMyThing = ValueOfMyThing };
    }
}
// ...

并致电Copy

List<IStuff> stuffList3 = stuffList1.Concat(stuffList2)
    .GroupBy(x => x.GetType())
    .Select(g => g.OrderByDescending(x => x.ValueOfMyThing).First().Copy())
    .ToList();

答案 1 :(得分:0)

第一,您需要让valueOfMyThing接口中的IStuff属性或字段成为类的合同。

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; }
}

然后添加此扩展方法以允许使用lambda参数进行独特查询:

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;
        }
    }
}

最后在列表中使用它。

List<IStuff> stuffList3 = new List<IStuff>();

stuffList3.AddRange(stuffList2);
stuffList3.AddRange(stuffList1);

var r = stuffList3.DistinctBy(x => x.valueOfMyThing);

答案 2 :(得分:0)

我需要创建对象的新实例。所以我最终这样做: 首先是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; }
}

然后根据此答案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);

        }

现在我有了一个新的具体课程列表,但是我不确定这是最好的方法