LINQ Extension Methods: Intersect

by wolfgang@gehirnwindung.de (Wolfgang) Mai 19, 2010 20:25

Mit der Intersect-Erweiterungsmethode vergleicht man zwei Sequenzen des gleichen Typs miteinander und erhält als Ergebnis eine neue Sequenz, in der die Elemente der ersten Sequenz vorhanden sind, die auch in der 2. Sequenz vorkommen (Gegenteilig zur Except-Erweiterungsmethode). Dabei wird jedes Element nur einmal aufgeführt. Verglichen wird - wenn man nichts anderes angibt - mit EqualityComparer<T>.Default.

Ohne Intersect Extension Method kann man das Verhalten in etwa so nachbilden

private List<T> Intersect<T>( List<T> list1, List<T> list2, EqualityComparer<T> comparer ) {
    var ret = new List<T>( );
    if( comparer == null ) comparer = EqualityComparer<T>.Default;

    for( int i = 0; i < list1.Count; i++ ) {
        if(
            !ret.Contains( list1[i], comparer ) &&
            list2.Contains( list1[i], comparer )
        ) {
            ret.Add( list1[i] );
        }
    }

    return ret;
}

Der Aufruf mit Erweiterungsmethode kann so erfolgen

list1.Intersect( list2 );
list1.Intersect( list2, EqualityComparer<T>.Default );

Tags: , ,

C#

LINQ Extension Methods: Except

by wolfgang@gehirnwindung.de (Wolfgang) Mai 12, 2010 21:00

Mittels Except-Erweiterungsmethode vergleicht man zwei Sequenzen des gleichen Typs miteinander und erhält als Ergebnis eine neue Sequenz, in der die Elemente der ersten Sequenz vorhanden sind, die in der 2. Sequenz nicht vorkommen. Dabei wird jedes Element nur einmal aufgeführt. Verglichen wird - wenn man nichts anderes angibt - mit EqualityComparer<T>.Default.

Ohne Except Extension Method kann man das Verhalten in etwa so nachbilden

private List<T> Except<T>( List<T> list1, List<T> list2, EqualityComparer<T> comparer ) {
    var ret = new List<T>( );
    if( comparer == null ) comparer = EqualityComparer<T>.Default;

    for( int i = 0; i < list1.Count; i++ ) {
        if(
            !ret.Contains( list1[i], comparer ) &&
            !list2.Contains( list1[i], comparer )
        ) {
            ret.Add( list1[i] );
        }
    }

    return ret;
}

Doch zum Glück gibt es die Erweiterungsmethoden, der Aufruf erfolgt in etwa so

list1.Except( list2 );
list1.Except( list2, EqualityComparer<T>.Default );

Tags: , ,

C#

LINQ Extension Methods: Union

by wolfgang@gehirnwindung.de (Wolfgang) Mai 12, 2010 01:00

Die Erweiterungsmethode Union bietet die Möglichkeit, 2 Sequenzen des gleichen Typs zu einer so zusammenzuführen, dass von jedem Element nur noch eine Entsprechung übrig bleibt. Damit verhält sich Union wie der Aufruf von Concat().Distinct().

Die Reihenfolge der Elemente in der Ergebnissequenz ergibt sich aus der Reihenfolge innerhalb der einzelnen Listen, die nacheinander abgearbeitet werden.

Ohne Union - Extension Method sieht das in etwa so aus

private List<T> Union<T>( List<T> list1, List<T> list2, EqualityComparer<T> comparer ) {
    var result = new List<T>( );
    if( comparer == null ) comparer = EqualityComparer<T>.Default;
    for( int i = 0; i < list1.Count; i++ ) {
        if( !result.Contains( list1[1], comparer ) ) {
            result.Add( list1[i] );
        }
    }

    for( int i = 0; i < list2.Count; i++ ) {
        if( !result.Contains( list2[1], comparer ) ) {
            result.Add( list2[i] );
        }
    }

    return result;
}

Der Vergleich wird - wenn nicht anders angegeben - mit dem Default - EqualityComparer<T> vollzogen.

Genauso verhält sich auch die Union-Erweiterungsmethode, die wie folgt aufgerufen wird

list1.Union( list2 );
list1.Union( list2, EqualityComparer<T>.Default );

Tags: , ,

C#

LINQ Extension Methods: Zip

by wolfgang@gehirnwindung.de (Wolfgang) Mai 11, 2010 18:51

Mit der Zip-Erweiterungsmethode können die Elemente zweier Sequenzen 1:1 zusammengeführt werden. Das Ergebnis ist eine neue Sequenz.
Zip ist somit eine spezialisierte Form von Join, wobei der Index als Key verwendet wird. Daher ist es auch egal, wie viele Elemente die jeweiligen Listen haben - zurückgegeben werden nur diejenigen Elemente, die in beiden Listen vorkommen.

Angenommen, man hat die 2 Listen firstNames und lastNamens mit den Vor- bzw. Nachnamen und möchte diese miteinander so kombinieren, dass eine string-Sequenz herauskommt, in der diese Namen durch Komma getrennt zusammengesetzt stehen. Die beiden Listen sind entsprechend sortiert.

Ohne Zip-Methode würde das in etwa so aussehen

var fullNames = new List<string>();
int count = Math.Min( firstNames.Count, lastNames.Count );
for( int i=0; i<count; i++ ){
    fullNames.Add( string.Format( "{1}, {0}", firstNames[i], lastNames[i] ) );
}

wobei die 2. Zeile vereinfacht werden kann, wenn sichergestellt ist, dass die beiden Listen gleich viele Elemente enthalten.

Mit der Zip-Methode geht das wesentlich kürzer (und ist meiner Meinung nach auch etwas leichter lesbar).
Wer noch Probleme mit den Lambda-Ausdrücken hat, der kann sich mit dem Artikel Tanz den => Lambda mit mir... ein wenig einlesen.

var fullNames = firstNames.Zip(
                    lastNames,
                    ( firstName, lastName ) => string.Format( "{1}, {0}", firstName, lastName )
                );

Der Rückgabewert ist nicht auf string-Sequenzen beschränkt. Es kann eine beliebige Klasse (z.B. eine anonymen Klasse) angegeben werden.

Z.B. ist fullNames hier

var fullNames = firstNames.Zip(
                    lastNames,
                    ( firstName, lastName ) => new {
                                                     FirstName = firstName,
                                                     LastName = lastName
                                               }
                );

eine Sequenz von Klassen, in denen die Eigenschaften FirstName und LastName gesetzt sind.

Tags: , ,

C#

Powered by BlogEngine.NET 1.6.1.6
Theme by Mads Kristensen | Modified by Mooglegiant and me ;)