5

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

但我只能在结果变量 (matches and unmatches) 中获得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; }
     }
4

5 回答 5

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

您可能想在访问之前检查 null ID,但它应该可以工作。

于 2013-05-11T12:51:08.833 回答
2

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

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

您还有一个问题:将具有两种不同类型的两个集合相交将导致 Object (公共父类)的集合。然后你必须投很多(反模式)。我建议你为你的模板类创建一个通用的抽象类/接口,它正在工作。如果您需要将元素转换回来,请不要转换,而是使用访问者模式: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 . . .
于 2013-05-11T12:25:54.300 回答
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));

matches并且unmatches都将IEnumerable<Template>是您需要的类型。

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

于 2013-05-11T13:19:08.007 回答
0

如前所述,实现IEqualityComparer<T>接口。

IEqualityComparer<T>MSDN

Except()然后在你的方法中使用它作为参数Intersect()

相交

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

于 2013-05-11T12:36:41.810 回答
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 方法的一个缺点是您要遍历列表两次。

于 2013-05-11T12:47:05.743 回答