I have an IEnumerable
and an IEnumerable
that I want merged into an IEnumerable
where
Untested, but should work:
IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> t, IEnumerable<U> u) {
IEnumerator<T> et = t.GetEnumerator();
IEnumerator<U> eu = u.GetEnumerator();
for (;;) {
bool bt = et.MoveNext();
bool bu = eu.MoveNext();
if (bt != bu)
throw new ArgumentException("Different number of elements in t and u");
if (!bt)
break;
yield return new KeyValuePair<T, U>(et.Current, eu.Current);
}
}
I would use something along the lines of -
IEnumerable<KeyValuePair<T,U>> Merge<T,U>(IEnumerable<T> keyCollection, IEnumerable<U> valueCollection)
{
var keys = keyCollection.GetEnumerator();
var values = valueCollection.GetEnumerator();
try
{
keys.Reset();
values.Reset();
while (keys.MoveNext() && values.MoveNext())
{
yield return new KeyValuePair<T,U>(keys.Current,values.Current);
}
}
finally
{
keys.Dispose();
values.Dispose();
}
}
This should work correctly, and cleanup properly afterwards.
Note: As of .NET 4.0, the framework includes a .Zip
extension method on IEnumerable, documented here. The following is maintained for posterity and for use in .NET framework version earlier than 4.0.
I use these extension methods:
// From http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-zip-operator.aspx
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> func) {
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
if (func == null)
throw new ArgumentNullException("func");
using (var ie1 = first.GetEnumerator())
using (var ie2 = second.GetEnumerator())
while (ie1.MoveNext() && ie2.MoveNext())
yield return func(ie1.Current, ie2.Current);
}
public static IEnumerable<KeyValuePair<T, R>> Zip<T, R>(this IEnumerable<T> first, IEnumerable<R> second) {
return first.Zip(second, (f, s) => new KeyValuePair<T, R>(f, s));
}
EDIT: after the comments I'm obliged to clarify and fix some things:
The MSDN has the following Custom Sequence Operators example. And Welbog is right; if you have no index on the underlying data you have no guarantee that the operation does what you exspect.
Think about what you're asking a bit more closely here:
You want to combine two IEnumerables in which "the indexes of the elements joined together in the KeyValuePair are the same", but you "don't have a count or an index for the items I'm merging".
There's no guarantee your IEnumerables are even sorted or unsorted. There's no correlation between your two IEnumerable objects, so how can you expect to correlate them?
Look at nextension:
Currently Implemented Methods
IEnumerable
- ForEach Performs a specified action on each element of the IEnumerable.
- Clump Groups items into same size lots.
- Scan Creates a list by applying a delegate to pairs of items in the IEnumerable.
- AtLeast Checks there are at least a certain amount of items in the IEnumerable.
- AtMost Checks there are no more than a certain amount of items in the IEnumerable.
- Zip Creates a list by combining two other lists into one.
- Cycle Creates a list by repeating another list.