2012-03-29 9 views

Antwort

1
var a = new List<int>(); 
var b = new List<int>(); 
var c = new List<int>(); 
var d = new List<int>(); 

c = a.Where(aItem => b.Any(bItem => aItem == bItem)).ToList(); 
d = a.Except(c).ToList(); 

Sie können eine beliebige Logik zum Vergleichen von aItem mit bItem verwenden.

Hier sind Erweiterungsmethoden, um das zu tun.

public static class LinqEx 
{ 
    public static bool DefaultCompare<T>(T one, T two) 
    { 
     return one.Equals(two); 
    } 

    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second) 
    { 
     return first.Common(second, DefaultCompare); 
    } 

    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, bool> compare) 
    { 
     return first.Where(i1 => second.Any(i2 => compare(i1, i2))); 
    } 

    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out IEnumerable<T> difference) 
    { 
     return first.Common(second, out difference, DefaultCompare); 
    } 

    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out IEnumerable<T> difference, Func<T, T, bool> compare) 
    { 
     var common = first.Common(second, compare); 

     difference = first.Except(common); 

     return common; 
    } 

    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out List<T> difference) 
    { 
     IEnumerable<T> d; 
     var common = first.Common(second, out d); 
     difference = d.ToList(); 

     return common; 
    } 

    public static IEnumerable<T> Common<T>(this IEnumerable<T> first, IEnumerable<T> second, out List<T> difference, Func<T, T, bool> compare) 
    { 
     IEnumerable<T> d; 
     var common = first.Common(second, out d, compare); 
     difference = d.ToList(); 

     return common; 
    } 
} 

Verbrauch:

List<myObjectType> d; 
c = a.Common(b, out d, (i1, i2) => i1.Name == i2.Name).ToList(); 
0

Die kurze Antwort ist unten:

var c = listA.Join(listB, a => a.Name, b => b.Name, (a, b) => a).ToList(); 
var d = listA.Except(c).ToList(); 

Dadurch werden die beiden Listen auf der Grundlage der Name Eigenschaft jedes Objekts beitreten und die gemeinsamen Objekte zurück aus erste Liste. Die Except()-Methode gibt Objekte zurück, die sich in listA nicht in c befinden; Der Vergleich wird mit Object.ReferenceEquals() durchgeführt und die Methode schlägt fehl, wenn Sie (a, b) => a zu (a, b) => b ändern. Damit eine solche Situation vermeiden Sie eine IEqualityComparer<Person> implementieren und an die Methode Except() wie dies passieren:

var comparer = new PersonComparer(); // the class that implements IEqualityComparer<Person> 
var d = listA.Except(c, comparer).ToList(); 
+0

Ich habe 'Where' und 'Any' verwendet, um IEqualityComparer nicht implementieren zu müssen. Mit 'Any' können Sie ein einfaches Prädikat angeben, um die Elemente zu vergleichen. – SimpleVar

+1

@YoryeNathan - 'Where()' und 'Any()' in Ihrem Beispiel haben nichts mit 'IEqualityComparer' zu tun; Sie haben diese Methoden als Ersatz für 'Join()' verwendet. Eine Implementierung von 'IEqualityComparer' wird für die' Except() 'Methode empfohlen, um einen Vergleich durch Objektreferenz zu vermeiden und durch eine benutzerdefinierte Logik zu vergleichen (in diesem Fall - der Wert der' Name' Eigenschaft). – RePierre

+0

IEqualityComparer für jede Vergleichslogik implementieren? "Ja wirklich?" Any (item1 => item1.Name == item2) ist ein perfektes Vergleichsverfahren und es ist nicht erforderlich, dass eine ganze Klasse sie nach Namen vergleicht. – SimpleVar

1

Meine Antwort ist ähnlich wie die anderen hier, aber die Intersect() Methode für die erste Hälfte mit, die ist die einfachste und richtige Weg, ich fühle mich, den Satz von Elementen zu erhalten, die in beiden Sätzen vorhanden sein:

var a = new[] {new Person("Alice"), new Person("Bob")}; 
var b = new[] {new Person("Bob"), new Person("Charlie")}; 

var inBoth = a.Intersect(b, new PersonNameEqualityComparer()); 
var notInB = a.Except(b, , new PersonNameEqualityComparer()); 

inBoth Bob enthalten, während notInB Alice enthalten wird.

Das einzige Problem hier ist, dass Intersect einen Gleichheitsvergleich benötigt, der zwei Person-Objekte abrufen und anhand ihres Namens feststellen kann, ob sie gleich sind. Ich wünschte, wir könnten hier nur einen Lambda-Ausdruck angeben, aber bis dahin ist die Implementierung einfach genug:

class PersonNameEqualityComparer : IEqualityComparer<Person> 
{ 
    public bool Equals(Person x, Person y) 
    { 
     return x.Name == y.Name; 
    } 
    public int GetHashCode(Person obj) 
    { 
     return obj.Name.GetHashCode(); 
    } 
} 
Verwandte Themen