如何复制列表<>到另一个列表<>与c#中的比较

时间:2013-05-11 12:18:31

标签: c# .net list generics

我有两个Lists。我想根据 ID 获取匹配和不匹配的值,并将结果添加到另一个List。我可以使用Intersect/Except获得这两个。

但我只能在结果变量(匹配和不匹配)中获得 ID 。我需要模板中的所有属性。

List<Template> listForTemplate = new List<Template>();
List<Template1> listForTemplate1 = new List<Template1>();

 var matches = listForTemplate .Select(f => f.ID)
                      .Intersect(listForTemplate1 .Select(b => b.ID));

 var ummatches = listForTemplate .Select(f => f.ID)
                     .Except(listForTemplate1.Select(b => b.ID));

     public class Template
     {
       public string ID{ get; set; }
       public string Name{ get; set; }
       public string Age{ get; set; }
       public string Place{ get; set; }
       public string City{ get; set; }
       public string State{ get; set; }
       public string Country{ get; set; }
     }
     public class Template1
     {
         public string ID{ get; set; }
     }

5 个答案:

答案 0 :(得分:3)

如果您不想为此简单任务实现IEquality,则只需修改LINQ查询:

var matches = listForTemplate.Where(f => listForTemplate1.Any(b => b.ID == f.ID));

var unmatches = listForTemplate.Where(f => listForTemplate1.All(b => b.ID != f.ID));

您可能希望在访问ID之前检查null,但它应该有效。

答案 1 :(得分:2)

您正在寻找重载函数,第二个参数是IEqualityComparer。所以制作你的比较器(例如:http://www.blackwasp.co.uk/IEqualityComparer.aspx),并在intersect / except中使用相同的比较器。

对于通用部分:也许你应该有一个模板的通用接口,例如ObjectWithID描述该类具有字符串ID属性。或者只是在比较器中使用dynamic(但我认为这是非常非常反模式的,因为如果使用错误类型,可能会出现运行时错误。)

您还有一个问题:两个不同类型的集合相交会产生一个Object(公共父类)的集合。然后你必须投了很多(反模式)。我建议你为你的模板类创建一个通用的抽象类/接口,它正在工作。如果你需要将元素强制转换,请不要强制转换,而是使用visitior模式:http://en.wikipedia.org/wiki/Visitor_pattern

示例(好):

    static void Main(string[] args)
    {
        // http://stackoverflow.com/questions/16496998/how-to-copy-a-list-to-another-list-with-comparsion-in-c-sharp

        List<Template> listForTemplate = new Template[] {
            new Template(){ID = "1"},
            new Template(){ID = "2"},
            new Template(){ID = "3"},
            new Template(){ID = "4"},
            new Template(){ID = "5"},
            new Template(){ID = "6"},
        }.ToList();

        List<Template1> listForTemplate1 = new Template1[] {
            new Template1(){ID = "1"},
            new Template1(){ID = "3"},
            new Template1(){ID = "5"}
        }.ToList();

        var comp = new ObjectWithIDComparer();

        var matches = listForTemplate.Intersect(listForTemplate1, comp);
        var ummatches = listForTemplate.Except(listForTemplate1, comp);

        Console.WriteLine("Matches:");
        foreach (var item in matches) // note that item is instance of ObjectWithID
        {
            Console.WriteLine("{0}", item.ID);
        }
        Console.WriteLine();

        Console.WriteLine("Ummatches:");
        foreach (var item in ummatches) // note that item is instance of ObjectWithID
        {
            Console.WriteLine("{0}", item.ID);
        }
        Console.WriteLine();
    }
}

public class ObjectWithIDComparer : IEqualityComparer<ObjectWithID>
{
    public bool Equals(ObjectWithID x, ObjectWithID y)
    {
        return x.ID == y.ID;
    }

    public int GetHashCode(ObjectWithID obj)
    {
        return obj.ID.GetHashCode();
    }
}

public interface ObjectWithID {
    string ID { get; set; }
}

public class Template : ObjectWithID
{
    public string ID { get; set; }
    public string Name { get; set; }
    public string Age { get; set; }
    public string Place { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }
}
public class Template1 : ObjectWithID
{
    public string ID { get; set; }
}

输出:

Matches:
1
3
5

Ummatches:
2
4
6

Press any key to continue . . .

答案 2 :(得分:1)

为了比较,这也应该有效(第一部分是@ MAV答案的变体):

var matches = from item in listForTemplate
              join id in listForTemplate1 on item.ID equals id.ID
              select item;

var unmatches = listForTemplate.Where(item => matches.All(elem => elem.ID != item.ID));

matchesunmatches都是IEnumerable<Template>,这是您需要的类型。

但是,MAV的答案很好,所以我会选择那个。

答案 3 :(得分:0)

如上所述,实施IEqualityComparer<T>界面。

IEqualityComparer<T> MSDN

然后在Except()Intersect()

的方法中将其用作参数

Intersect

有一个很好的示例,说明如何在Intersect()方法的链接上执行此操作。

答案 4 :(得分:0)

如果您不必使用LINQ,为什么不编写类似这样的代码?

    var matches = new List<Template>();
    var unmatches = new List<Template>();

    foreach (var entry in listForTemplate)
    {
        bool matched = false;
        foreach (var t1Entry in listForTemplate1)
        {
            if (entry.ID == t1Entry.ID)
            {
                matches.Add(entry);
                matched = true;
                break;
            }
        }
        if (!matched)
        {
            unmatches.Add(entry);
        }
    }

LINQ方法的一个缺点是你要遍历列表两次。