简体   繁体   English

如何使用c#中的Comparsion将List <>复制到另一个List <>

[英]How to copy a List<> to another List<> with Comparsion in c#

I an having Two Lists . 我有两个Lists I want to get the matched and unmatched values based on ID and add the results to another List . 我想根据ID获取匹配和不匹配的值,并将结果添加到另一个List I can get both of these using Intersect/Except . 我可以使用Intersect/Except来获得这两个。

But I can get only ID in the resultant variables (matches and unmatches) . 但是我只能在结果变量(匹配和不匹配)中获得ID I need all the properties in the Template. 我需要模板中的所有属性。

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

If you don't want to implement IEquality for this simple task, you can just modify your LINQ queries: 如果您不想为此简单任务实现IEquality ,则只需修改LINQ查询:

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

and

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

You might want to check for null before accessing ID , but it should work. 您可能希望在访问ID之前检查null,但它应该可以工作。

You are looking for the overloaded function, with the second parameter IEqualityComparer. 您正在寻找重载函数,第二个参数是IEqualityComparer。 So make your comparer ( example: http://www.blackwasp.co.uk/IEqualityComparer.aspx ), and use the same comparer in intersect / except. 所以制作你的比较器(例如: http//www.blackwasp.co.uk/IEqualityComparer.aspx ),并在intersect / except中使用相同的比较器。

And for the generic part: maybe you should have a common interface for templates eg ObjectWithID describing that the class have a string ID property. 对于通用部分:也许你应该有一个模板的通用接口,例如ObjectWithID描述该类具有字符串ID属性。 Or simply use dynamic in your comparer (but I think this is very-very antipattern because you can have run time errors if using for the bad type). 或者只是在比较器中使用dynamic(但我认为这是非常非常反模式的,因为如果使用了错误的类型,你可能会遇到运行时错误)。

You also have a problem: intersecting two collections with two different types will result in a collection of Object (common parent class). 您还有一个问题:将两个不同类型的集合相交会产生一个Object(公共父类)的集合。 Then you have to cast a lot (antipattern). 然后你必须投了很多(反模式)。 I advise you to make a common abstract class/interface for your template classes, and it is working. 我建议你为你的模板类创建一个通用的抽象类/接口,它正在工作。 If you need to cast the elements back, do not cast, but use the visitior pattern: http://en.wikipedia.org/wiki/Visitor_pattern 如果您需要将元素强制转换,请不要强制转换,但请使用visitior模式: http//en.wikipedia.org/wiki/Visitor_pattern

Example (good): 示例(好):

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

Output: 输出:

Matches:
1
3
5

Ummatches:
2
4
6

Press any key to continue . . .

For comparison, this should also work (the first part is a variation on @MAV's answer): 为了比较,这也应该有用(第一部分是@ 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));

matches and unmatches will both be IEnumerable<Template> which is the type you require. matchesunmatches都是IEnumerable<Template> ,这是您需要的类型。

However, MAV's answer works fine so I'd go for that one. 但是,MAV的答案很好,所以我会选择那个。

As mentioned, Implement the IEqualityComparer<T> interface. 如上所述,实现IEqualityComparer<T>接口。

IEqualityComparer<T> MSDN IEqualityComparer<T> MSDN

Then use this as an argument in your method for Except() and Intersect() 然后在你的Except()Intersect()方法中使用它作为参数

Intersect 相交

There is a good example of how to do so on the link for the Intersect() method. 有关如何在Intersect()方法的链接上执行此操作的一个很好的示例。

If you don't absolutely have to use LINQ, why not code something like this? 如果您不一定要使用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);
        }
    }

A disadvantage of the LINQ approach is that you're traversing the lists twice. LINQ方法的缺点是您遍历列表两次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM