2012-03-22 3 views
1

Как совместить 2 коллекции таким образом, что результирующий коллекция содержит значения, альтернативно, из обеих коллекцийСлияние 2 коллекции

Пример: - Col А = [1,2,3,4] Колонка Б = [5,6,7,8]

Результат Col С = [1,5,2,6,3,7,4,8]

+3

бы коллекции всегда одной и той же длины? – Lander

+0

Каков тип коллекций A и B? Не имеет значения, какой тип имеет коллекция результатов C? – phoog

+0

Тип данных для коллекции может быть любой, и длина может отличаться. – praveen

ответ

2

Существует множество способов сделать это, в зависимости от типа ввода и требуемого типа вывода. Однако нет библиотечного метода, о котором я знаю; вам придется «сворачивать свои собственные».

Одним из возможных вариантов был бы метод итератора LINQ-стиль, при условии, что все, что мы знаем о входных коллекции является то, что они реализуют IEnumerable<T>:

static IEnumerable<T> Interleave(this IEnumerable<T> a, IEnumerable<T> b) 
{ 
    bool bEmpty = false; 
    using (var enumeratorB b.GetEnumerator()) 
    { 
     foreach (var elementA in a) 
     { 
      yield return elementA; 
      if (!bEmpty && bEnumerator.MoveNext()) 
       yield return bEnumerator.Current; 
      else 
       bEmpty = true; 
     } 
     if (!bEmpty) 
      while (bEnumerator.MoveNext()) 
       yield return bEnumerator.Current; 
    } 
} 
+0

Спасибо. Просто для любопытства Можем ли мы каким-то образом реализовать оператор ZIP в Linq, который является новым для .NET 4.0 для решения проблемы? – praveen

+0

Ответ @praveen Anthony Pegram использовал почтовый индекс, но он, кажется, удалил его. Это не самый эффективный способ выполнить, но это, безусловно, делает код менее сложным. Проблема в том, что он усекает более длинную последовательность, поэтому, если у вас есть входные коллекции с 4 и 5 элементами, соответственно, вывод будет содержать 8 элементов, и вы потеряете последний элемент во второй коллекции. Вот почему Энтони удалил свой ответ. – phoog

+0

Спасибо @phoog за разъяснение – praveen

2
int[] a = { 1, 2, 3, 4 }; 
int[] b = { 5, 6, 7, 8 }; 
int[] result = a.SelectMany((n, index) => new[] { n, b[index] }).ToArray(); 

Если сбор а и б не той же длины, вам нужно быть осторожным, чтобы использовать b[index], возможно, вам нужно: index >= b.Length ? 0 : b[index]

расширения
+0

Спасибо, что она решила мою проблему. – praveen

-2

Союза Используйте Linq, такие как:

var colA = new List<int> { 1, 2, 3, 4 }; 
var colB = new List<int> { 1, 5, 2, 6, 3, 7, 4, 8}; 

var result = colA.Union(colB); // 1, 2, 3, 4, 5, 6, 7, 8 
+3

«содержит значения в качестве альтернативы», поэтому индекс 0 из A остается, индекс 0 из B равен 1 в новом массиве и т. Д. – Lander

1

Предполагая, что оба коллекций имеют одинаковую длину:

Debug.Assert(a.Count == b.Count); 

for (int i = 0; i < a.Count; i++) 
{ 
    c.Add(a[i]); 
    c.Add(b[i]); 
} 

Debug.Assert(c.Count == (a.Count + b.Count)); 
2

Если коллекции не обязательно имеют одинаковую длину, рассмотрит метод расширения:

public static IEnumerable<T> AlternateMerge<T>(this IEnumerable<T> source, 
               IEnumerable<T> other) 
{ 
    using(var sourceEnumerator = source.GetEnumerator()) 
    using(var otherEnumerator = other.GetEnumerator()) 
    { 
     bool haveItemsSource = true; 
     bool haveItemsOther = true; 
     while (haveItemsSource || haveItemsOther) 
     { 
      haveItemsSource = sourceEnumerator.MoveNext(); 
      haveItemsOther = otherEnumerator.MoveNext(); 

      if (haveItemsSource) 
       yield return sourceEnumerator.Current; 

      if (haveItemsOther) 
       yield return otherEnumerator.Current; 
     } 
    } 
} 

И использовать:

List<int> A = new List<int> { 1, 2, 3 }; 
List<int> B = new List<int> { 5, 6, 7, 8 }; 

var mergedList = A.AlternateMerge(B).ToList(); 
+0

Многие перечислители выдают исключение, если вы вызываете MoveNext после получения ложного возвращаемого значения. Этот ответ не защищает от этого. – phoog

+1

Это не то, что говорят документы, и я не видел, что по крайней мере для регулярных коллекций (отлично работает) - появился пример такого поведения? (docs say ** Когда перечислитель находится в этой позиции, последующие вызовы MoveNext также возвращают false до вызова Reset. **) – BrokenGlass

+0

Нет, теперь, когда я опубликовал это, я не могу найти никаких подтверждающих доказательств. Я уверен, что видел это раньше. Возможно, это был проприетарный код, написанный кем-то, кто не читал документы. – phoog

Смежные вопросы