2011-02-10 5 views
40

Mam dwa zestawy datariów. Każda z nich jest niezliczona. Chcę dołączyć/połączyć te dwie listy w jedną listę. Jestem pewien, że to jest wykonalne. Nie chcę wykonywać pętli for i zauważyłem, że istnieje metoda unijna i metoda łączenia na dwóch listach. Jakieś pomysły?Dołączanie/łączenie dwóch ciągów IZumerowalnych

+0

Czy zestawy datariów tego samego typu? Różne rodzaje? – Oded

+0

@Obed .... są tego samego typu. – MikeTWebb

Odpowiedz

87

Zakładając, że twoje obiekty są tego samego typu, możesz użyć albo Union lub Concat. Zauważ, że podobnie jak słowo kluczowe SQL UNION, operacja Union zapewni wyeliminowanie duplikatów, natomiast Concat (jak UNION ALL) po prostu doda drugą listę do końca pierwszej.

IEnumerable<T> first = ...; 
IEnumerable<T> second = ...; 

IEnumerable<T> combined = first.Concat(second); 

lub

IEnumerable<T> combined = first.Union(second); 

Jeśli są one z różnych rodzajów, a następnie trzeba będzie Select nich w coś wspólnego. Np

IEnumerable<TOne> first = ...; 
IEnumerable<TTwo> second = ...; 

IEnumerable<T> combined = first.Select(f => ConvertToT(f)).Concat(
          second.Select(s => ConvertToT(s))); 

przypadku ConvertToT(TOne f) i ConvertToT(TTwo s) reprezentuje operację, która w jakiś sposób przekształca wystąpienie TOne (i TTwo, odpowiednio) do instancji T.

+0

@Adam ... fantastyczne .... właśnie to, czego potrzebowałem – MikeTWebb

+0

@Adam .... Mówiłem zbyt szybko. Zrobiłem w Unii Dostaję duplikaty rekordów. Czy należy zainicjować kluczową właściwość jakiegoś rodzaju? – MikeTWebb

+1

@MikeTWebb: 'Union' ma przeciążenie, które pozwala ci określić' IEqualityComparer'. –

1

Po prostu spotkałem się z podobną sytuacją, w której potrzebuję połączyć wiele sekwencji.

Naturalnie szukał istniejących rozwiązań w Google/StackOverflow, jednak nie znalazł niczego, co nie wyliczyło przeliczalnych, np. przekonwertować do tablicy następnie użyć Array.Copy() itp., więc napisałem rozszerzenie i statyczną metodę utiltiy o nazwie ConcatMultiple.

Mam nadzieję, że to pomoże każdemu, kto musi zrobić to samo.

/// <summary> 
/// Concatenates multiple sequences 
/// </summary> 
/// <typeparam name="TSource">The type of the elements of the input sequences.</typeparam> 
/// <param name="first">The first sequence to concatenate.</param> 
/// <param name="source">The other sequences to concatenate.</param> 
/// <returns></returns> 
public static IEnumerable<TSource> ConcatMultiple<TSource>(this IEnumerable<TSource> first, params IEnumerable<TSource>[] source) 
{ 
    if (first == null) 
     throw new ArgumentNullException("first"); 

    if (source.Any(x => (x == null))) 
     throw new ArgumentNullException("source"); 

    return ConcatIterator<TSource>(source); 
} 

private static IEnumerable<TSource> ConcatIterator<TSource>(IEnumerable<TSource> first, params IEnumerable<TSource>[] source) 
{ 
    foreach (var iteratorVariable in first) 
     yield return iteratorVariable; 

    foreach (var enumerable in source) 
    { 
     foreach (var iteratorVariable in enumerable) 
      yield return iteratorVariable; 
    } 
} 

/// <summary> 
/// Concatenates multiple sequences 
/// </summary> 
/// <typeparam name="TSource">The type of the elements of the input sequences.</typeparam>   
/// <param name="source">The sequences to concatenate.</param> 
/// <returns></returns> 
public static IEnumerable<TSource> ConcatMultiple<TSource>(params IEnumerable<TSource>[] source) 
{ 
    if (source.Any(x => (x == null))) 
     throw new ArgumentNullException("source"); 

    return ConcatIterator<TSource>(source); 
} 

private static IEnumerable<TSource> ConcatIterator<TSource>(params IEnumerable<TSource>[] source) 
{ 
    foreach (var enumerable in source) 
    { 
     foreach (var iteratorVariable in enumerable) 
      yield return iteratorVariable; 
    } 
} 
1

Sposób Join jest jak SQL przyłączyć, gdzie liście są Krzyż określany w oparciu o warunek, że nie jest to ciąg konkatenacji lub dodanie do listy. Metoda Union robi to, co chcesz, podobnie jak metoda Concat, ale obie są LAZY ocenia i mają wymaganie, aby parametry miały wartość inną niż null. Zwracają albo ConcatIterator albo UnionIterator i if called repeatedly this could cause problems. Chętna ocena skutkuje odmiennym zachowaniem, jeśli tego właśnie chcesz, można użyć metody rozszerzenia, takiej jak ta poniżej.

public static IEnumerable<T> myEagerConcat<T>(this IEnumerable<T> first, 
                IEnumerable<T> second) 
{ 
    return (first ?? Enumerable.Empty<T>()).Concat(
      (second ?? Enumerable.Empty<T>())).ToList(); 
}