2012-05-17 2 views
18

Я осмотрелся и не могу найти ничего, чтобы помочь здесь. У меня есть класс:C# Linq пересекается/за исключением одной части объекта

class ThisClass 
{ 
    private string a {get; set;} 
    private string b {get; set;} 
} 

Я хотел бы использовать Intersect и кроме методов Linq, т.е .:

private List<ThisClass> foo = new List<ThisClass>(); 
private List<ThisClass> bar = new List<ThisClass>(); 

Затем я заполнить два списка отдельно. Я хотел бы сделать, например, (и я знаю, что это не так, просто псевдокод), следующее:

foo[a].Intersect(bar[a]); 

Как мне это сделать?

Спасибо за любую помощь :)

+0

Что вам нужно? Объясните словами, что вы хотите от этой строки 'foo [a] .Intersect (bar [a]);'. –

ответ

25

Может

// returns list of intersecting property 'a' values 
foo.Select(f => f.a).Intersect(bar.Select(b => b.a)); 

BTW недвижимость a должны быть публичными.

+0

Ницца, просто, делает то, что мне нужно. Спасибо вам и всем ответчикам. –

16

Если вам нужен список одного объекта, который вы хотели бы пересечь, тогда все остальные красивые решения LINQ работают нормально. НО! Если вы хотите пересечься по всему классу, и в результате получим List<ThisClass> вместо List<string>, вам придется написать свой собственный сопоставитель сравнений.

foo.Intersect(bar, new YourEqualityComparer()); 

с Except.

public class YourEqualityComparer: IEqualityComparer<ThisClass> 
{ 

    #region IEqualityComparer<ThisClass> Members 


    public bool Equals(ThisClass x, ThisClass y) 
    { 
     //no null check here, you might want to do that, or correct that to compare just one part of your object 
     return x.a == y.a && x.b == y.b; 
    } 


    public int GetHashCode(ThisClass obj) 
    { 
     unchecked 
     { 
      var hash = 17; 
          //same here, if you only want to get a hashcode on a, remove the line with b 
      hash = hash * 23 + obj.a.GetHashCode(); 
      hash = hash * 23 + obj.b.GetHashCode(); 

      return hash;  
     } 
    } 

    #endregion 
} 
-2

Вы должны создать IEqualityComparer. Вы можете передать метод IEqualityComparer в метод Intersect(). Это поможет вам легче получить список (который пересекает панель).

var intersectionList = foo.Intersect(bar, new ThisClassEqualityComparer()).ToList(); 


class ThisClassEqualityComparer : IEqualityComparer<ThisClass> 
{ 

    public bool Equals(ThisClass b1, ThisClass b2) 
    { 
     return b1.a == b2.a; 
    } 


    public int GetHashCode(Box bx) 
    { 
     // To ignore to compare hashcode, please consider this. 
     // I would like to force Equals() to be called 
     return 0; 
    } 

} 
+1

Вы не должны возвращать '0' из хеш-кода, как это. Это полностью уничтожит производительность. Вместо этого вы должны использовать хеш-код 'a'. – Servy

0

Что именно представляет собой желаемый эффект? Вы хотите получить список строк, состоящий из всех a в ваших классах, или список ThisClass, когда два экземпляра ThisClass идентифицируются уникальными значениями a?

Если это первый, два ответа от @lazyberezovksy и @Tilak должны работать. Если это последнее, вы должны переопределить IEqualityComparer<ThisClass> или IEquatable<ThisClass> так, что Intersect знает, что делает два экземпляра ThisClass эквивалент:

private class ThisClass : IEquatable<ThisClass> 
{ 
    private string a; 

    public bool Equals(ThisClass other) 
    { 
     return string.Equals(this.a, other.a); 
    } 
} 

, то вы можете просто позвонить:

var intersection = foo.Intersect(bar);  
+1

При реализации 'IEquatable' вам всегда нужно переопределять' GetHashCode'. Поскольку вы этого не сделаете, это не сработает. – Servy

3

Не уверен, что из скорость этого по сравнению с пересечением и сравнить, но как насчет:

//Intersect 
var inter = foo.Where(f => bar.Any(b => b.a == f.a)); 
//Except - values of foo not in bar 
var except = foo.Where(f => !bar.Any(b => b.a == f.a)); 
+3

Это алгоритм O (n * m), тогда как 'Intersect' и' Except' являются «O (n + m)». Это делает вас намного хуже. Он также выполняет многократное повторение «бара», что может быть серьезной проблемой во всех ситуациях (это может не дать одинаковых результатов на каждой итерации, оно может запрашивать базу данных или преформировать дорогостоящие вычисления на каждой итерации, может иметь побочные эффекты вызванные при повторении и т. д. – Servy

0

Я знаю, что это старый, но вы не могли бы lso просто переопределить Equals & GetHashCode на самом классе?

class ThisClass 
{ 
    public string a {get; set;} 
    private string b {get; set;} 

    public override bool Equals(object obj) 
    { 
    // If you only want to compare on a 
    ThisClass that = (ThisClass)obj; 
    return string.Equals(a, that.a/* optional: not case sensitive? */); 
    } 

    public override int GetHashCode() 
    { 
    return a.GetHashCode(); 
    } 
}