如何将两种类型的C#列表合并为一个?

Sha*_*eek 15 c# linq ienumerable

我创建了两个名为X&Y的列表.这两个列表的类型不同.(即List<class_A> X&List<class_B> Y).

这两个列表中的值都不同.但是这DateTime两个列表中都有一个字段.

我需要根据date字段对这些列表进行排序.

我有单独的函数来打印列表A和列表B的详细信息.

假设排序列表看起来像

  • 列表A中的元组,
  • 列表B中的元组,
  • 列表A中的元组,
  • 列表B中的元组,

我的目的是遍历此列表并调用相应的函数来显示详细信息.即,如果元组来自列表A,则调用函数打印列表A的详细信息,反之亦然.

sla*_*win 27

您可以创建一个interface托管公共属性和函数的函数,然后在转换为此接口后将这些列表连接起来然后对其进行排序:

interface ICommon
{
    DateTime DT { get; }
    void Print();
}
class ClassA : ICommon
{
    public DateTime DT { get; set; }
    public void Print() { Console.WriteLine("A " + DT); }
}
class ClassB : ICommon
{
    public DateTime DT { get; set; }
    public void Print() { Console.WriteLine("B " + DT); }
}

public static void Main()
{
    var listA = new List<ClassA> { new ClassA() { DT = DateTime.Now.AddDays(-1) }, new ClassA() { DT = DateTime.Now.AddDays(-3) }};
    var listB = new List<ClassB> { new ClassB() { DT = DateTime.Now.AddDays(-2) }, new ClassB() { DT = DateTime.Now.AddDays(-4) }};

    var orderedResult = listA.Cast<ICommon>()
                             .Concat(listB.Cast<ICommon>())
                             .OrderBy(q => q.DT);
    //or possibly even better:
    //var orderedResult = listA.Concat<ICommon>(listB).OrderBy(q => q.DT);
    foreach (var obj in orderedResult)
        obj.Print();
}
Run Code Online (Sandbox Code Playgroud)

  • @slawekwin:为什么你认为删除对`.Cast <T>`的不必要的调用是"可读性命中"?我个人认为`Kyle`的版本更清晰_(实际上,我会更进一步明确地将`listA`和`listB`定义为`IEnumerable <ICommon>`开始.然后代码变为`listA .Concat(数组listB)`)_ (4认同)
  • 我认为,无论哪种方式,可读性都是次要问题.使用.Cast的真正问题是你失去了类型安全性,并让自己对InvalidCastException开放.使用Concat <ICommon>是类型安全的,因为如果任何一种类型不可转换,您将收到编译器错误. (4认同)
  • 如果明确提供`Concat`的泛型参数,则可以删除两个`Cast`调用.即`listA.Concat <ICommon>(listB)`.只需保存一点打字.或者你也可以出于类似的原因在`listB`上删除`Cast`调用. (3认同)
  • @Boris谢谢,现在应该会更好 (2认同)

Mat*_*son 22

如果你可以改变A和类的定义,B那么你应该使用其中一个其他答案,告诉你为这两个类添加一个接口.

但是,如果您无法更改A和类的定义B(可能是因为它们是在您无法更改的库中定义的),那么您必须采用不同的方法.

一个保持相当整洁的解决方案是引入一个包装类,它包含类A或类的实例B(但不包括两者).

假设您的类看起来像这样:

class A
{
    public DateTime Date;
    public double Value;
    public void Print() {}
}

class B
{
    public DateTime Date;
    public string Value;
    public void Print() { }
}
Run Code Online (Sandbox Code Playgroud)

您可以编写一个如下所示的简单包装器:

class Wrapper
{
    readonly A a;
    readonly B b;

    public Wrapper(A a)
    {
        this.a = a;
    }

    public Wrapper(B b)
    {
        this.b = b;
    }

    public DateTime Date => a?.Date ?? b.Date;

    public void Print()
    {
        if (a != null)
            a.Print();
        else
            b.Print();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后给出两个列表:

var listA = new List<A>();
var listB = new List<B>();
Run Code Online (Sandbox Code Playgroud)

您可以创建Wrapper对象的排序列表:

var sorted = 
    listA.Select(a => new Wrapper(a))
    .Concat(listB.Select(b => new Wrapper(b)))
    .OrderBy(item => item.Date);
Run Code Online (Sandbox Code Playgroud)

然后为Print()排序列表中的每个项调用适当的方法:

foreach (var item in sorted)
    item.Print();
Run Code Online (Sandbox Code Playgroud)


Ste*_*els 7

如果你制作Class AClass B以a为基础Base class,你可以让他们从中获得你的DateTime财产Base class.

例如:

public class BaseClass
{
    public DateTime date {get; set; }
}

public class ClassA : BaseClass
{
    //... some other property's
}

public class ClassB : BaseClass
{
    //... some other property's
}
Run Code Online (Sandbox Code Playgroud)

在你的代码中:

List<BaseClass> a = new List<ClassA>();
List<BaseClass> b = new List<ClassB>();
Run Code Online (Sandbox Code Playgroud)

因为ClassA和ClassB基于BaseClass,它们将具有相同的date属性.

  • 使`BaseClass`抽象(更好)或使用接口(最好) (3认同)

Boj*_*n B 6

您可以为您拥有的2个类创建一个简单的界面:

public interface interfaceA {
   DateTime TimeStamp { get;set; }
}
Run Code Online (Sandbox Code Playgroud)

并确保您的类都实现该接口:

public class class_A : interfaceA {
    public DateTime TimeStamp { get; set; }
    //... Other properties
}

public class class_B : interfaceA {
    public DateTime TimeStamp { get; set; }
    //... Other properties
}
Run Code Online (Sandbox Code Playgroud)

在您的主函数/方法中,您创建一个包含两种对象类型并填充它的新List - 而不是填充您的2个列表中的一个,您只需填写以下列表:

var myList = new List<interfaceA>();
var object = new class_A() { TimeStamp = DateTime.Now };
myList.Add(object); 
Run Code Online (Sandbox Code Playgroud)

然后对它进行排序:

 myList.Sort((a, b) => a.TimeStamp.CompareTo(b.TimeStamp))
Run Code Online (Sandbox Code Playgroud)

我觉得这样的事情应该有效


Bur*_*sBA 5

无需创建新的接口或类.您可以同时遍历两个列表并跟踪最近的日期.

public class TypeA
{
    public DateTime date { get; set; }
    public void Print() { Console.WriteLine("TypeA: " + date.ToString()); }
}

public class TypeB
{
    public DateTime date { get; set; }
    public void Print() { Console.WriteLine("TypeB: " + date.ToString()); }
}

class Program
{
    static void Main(string[] args)
    {
        // setup
        var X = new List<TypeA>();
        var Y = new List<TypeB>();

        Random rnd = new Random();
        int imin, imax;

        imin = rnd.Next(3, 7);
        imax = rnd.Next(10, 20);

        for (int i = imin; i < imax; i++)
        {
            X.Add(new TypeA() { date = DateTime.Now.AddDays(-1 * rnd.Next(1, 1000)) });
        }

        imin = rnd.Next(3, 7);
        imax = rnd.Next(10, 20);

        for (int i = imin; i < imax; i++)
        {
            Y.Add(new TypeB() { date = DateTime.Now.AddDays(-1 * rnd.Next(1, 1000)) });
        }

        X = X.OrderBy(z => z.date).ToList();
        Y = Y.OrderBy(z => z.date).ToList();

        // begin print in order

        // index for X list
        int ix = 0;

        // index for Y list
        int iy = 0;

        // most recently printed date
        DateTime min = DateTime.MinValue;

        while (true)
        {
            if (ix < X.Count && X[ix].date >= min && (iy >= Y.Count || iy < Y.Count && X[ix].date <= Y[iy].date))
            {
                X[ix].Print();
                min = X[ix].date;
                ix++;
                continue;
            }

            if (iy < Y.Count && Y[iy].date >= min)
            {
                Y[iy].Print();
                min = Y[iy].date;
                iy++;
            }

            if (ix >= X.Count && iy >= Y.Count)
            {
                break;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

样本输出:

TypeB: 12/19/2013 3:44:44 PM
TypeB: 2/19/2014 3:44:44 PM
TypeB: 5/1/2014 3:44:44 PM
TypeA: 5/27/2014 3:44:44 PM
TypeA: 6/6/2014 3:44:44 PM
TypeA: 7/12/2014 3:44:44 PM
TypeA: 7/18/2014 3:44:44 PM
TypeB: 12/5/2014 3:44:44 PM
TypeB: 5/3/2015 3:44:44 PM
TypeB: 5/4/2015 3:44:44 PM
TypeB: 8/9/2015 3:44:44 PM
TypeA: 8/25/2015 3:44:44 PM
TypeA: 9/20/2015 3:44:44 PM
TypeB: 9/26/2015 3:44:44 PM
TypeA: 10/12/2015 3:44:44 PM
TypeA: 12/7/2015 3:44:44 PM
TypeB: 12/19/2015 3:44:44 PM
TypeA: 4/13/2016 3:44:44 PM
TypeA: 5/23/2016 3:44:44 PM
TypeB: 8/4/2016 3:44:44 PM
TypeB: 8/11/2016 3:44:44 PM
Run Code Online (Sandbox Code Playgroud)


Mah*_*hdi 0

创建具有其他两个类的属性的第三个类。然后创建其对象列表并按日期时间对其进行排序。

  • 一个接口就足够了,不需要使用第三个类。 (7认同)