List<double> a = new List<double>{1,2,3};
List<double> b = new List<double>{1,2,3,4,5};
a + b should give me {2,4,6,4,5}.
Obviously I can write a loop, but is there a better way? Using LINQ?
List<double> a = new List<double>{1,2,3};
List<double> b = new List<double>{1,2,3,4,5};
a + b should give me {2,4,6,4,5}.
Obviously I can write a loop, but is there a better way? Using LINQ?
You could use a modified "zip" operation easily enough, but nothing built in. Something like:
static void Main() {
var a = new List<int> { 1, 2, 3 };
var b = new List<int> { 1, 2, 3, 4, 5 };
foreach (var c in a.Merge(b, (x, y) => x + y)) {
Console.WriteLine(c);
}
}
static IEnumerable<T> Merge<T>(this IEnumerable<T> first,
IEnumerable<T> second, Func<T, T, T> operation) {
using (var iter1 = first.GetEnumerator())
using (var iter2 = second.GetEnumerator()) {
while (iter1.MoveNext()) {
if (iter2.MoveNext()) {
yield return operation(iter1.Current, iter2.Current);
} else {
yield return iter1.Current;
}
}
while (iter2.MoveNext()) {
yield return iter2.Current;
}
}
}
operation isn't called for non-existing items. We ended up modifying it to call operation with default(T) passed for missing operand. Thanks!Using .NET 4.0's Zip operator:
var sums = b.Zip(a, (x, y) => x + y)
.Concat(b.Skip(a.Count()));
If you want to generalize this, check which has more elements and use that as the "b" above.
Enumerable.Range(0, new[] { a.Count, b.Count }.Max())
.Select(n => a.ElementAtOrDefault(n) + b.ElementAtOrDefault(n));
Math.Max(a.Count, b.Count) instead of new[] { a.Count, b.Count }.Max().a.Count > n ? a[n] : 0 instead.I had to slightly adjust Marc's solution for my use to allow for lists of different types, so I thought I'd post in incase anyone else needs it.
public static IEnumerable<TResult> Merge<TFirst,TSecond,TResult>(this IEnumerable<TFirst> first,
IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> operation) {
using (var iter1 = first.GetEnumerator()) {
using (var iter2 = second.GetEnumerator()) {
while (iter1.MoveNext()) {
if (iter2.MoveNext()) {
yield return operation(iter1.Current, iter2.Current);
} else {
yield return operation(iter1.Current, default(TSecond));
}
}
while (iter2.MoveNext()) {
yield return operation(default(TFirst), iter2.Current);
}
}
}
}
The way to do this with just Zip is:
b.Zip(a.DefaultIfEmpty(), (x,y) => x+y)
As default value of numeric types is 0 you don't need any extra handling.
DefaultIfEmpty() does not do what you think it does. It returns a single default element if sequence a is empty. It does not provide additional items for an already existing sequence!How about this:
List<double> doubles = Enumerable.Range(0, Math.Max(a.Count, b.Count))
.Select(x => (a.Count > x ? a[x] : 0) + (b.Count > x ? b[x] : 0))
.ToList();
Below is a solution to your problem.
List<double> a = new List<double>{1,2,3};
List<double> b = new List<double>{1,2,3,4,5};
List<double> sum = new List<double>();
int max = Math.Min(a.Count, b.Count);
for (int i = 0; i < max; i++){
sum.Add(a[i] + b[i]);
}
if (a.Count < b.Count)
for (int i = max i < b.Count)
sum.Add(b[i]);
else
for (int i = max i < a.Count)
sum.Add(a[i]);
In this case, whether lists are of the same length, or of different lengths, it doesn't really matter. .NET class library doesn't have Enumerable.Zip method to combine two sequences (it will only come in .NET 4.0), and you would need something like that here either way. So you either have to write a loop, or to write your own Zip (which would still involve a loop).
There are some hacks to squeeze this all in a single LINQ query without loops, involving joining on indices, but those would be very slow and really pointless.
What happened to the 1 and the extra 2 and 3? If you're looking for distinct values:
var one = new List<int> { 1, 2, 3 };
var two = new List<int> { 1, 2, 3, 4, 5 };
foreach (var x in one.Union(two)) Console.Write("{0} ", x);
Will give you 1 2 3 4 5
If you're looking for just the second list appended to the first then:
foreach(var x in one.Concat(two)) // ...
will give you 1 2 3 1 2 3 4 5
Edit: Oh, I see, you're looking for a sort of Zip, but which returns the extra parts. Try this:
public static IEnumerable<V> Zip<T, U, V>(
this IEnumerable<T> one,
IEnumerable<U> two,
Func<T, U, V> f)
{
using (var oneIter = one.GetEnumerator()) {
using (var twoIter = two.GetEnumerator()) {
while (oneIter.MoveNext()) {
twoIter.MoveNext();
yield return f(oneIter.Current,
twoIter.MoveNext() ?
twoIter.Current :
default(U));
}
while (twoIter.MoveNext()) {
yield return f(oneIter.Current, twoIter.Current);
}
}
}
}
and here's one that's more like a normal zip function, which doesn't return the extras:
public static IEnumerable<V> Zip<T, U, V>(
this IEnumerable<T> one,
IEnumerable<U> two,
Func<T, U, V> f)
{
using (var oneIter = one.GetEnumerator()) {
using (var twoIter = two.GetEnumerator()) {
while (oneIter.MoveNext()) {
yield return f(oneIter.Current,
twoIter.MoveNext() ?
twoIter.Current :
default(U));
}
}
}
}
Example usage:
var one = new List<int> { 1, 2, 3, 4, 5};
var two = new List<char> { 'h', 'e', 'l', 'l', 'o' };
foreach (var x in one.Zip(two, (a,b) => new {A = a, B =b }))
Console.WriteLine("{0} => '{1}'", x.A, x.B);
Results in:
1 => 'h'
2 => 'e'
3 => 'l'
4 => 'l'
5 => 'o'
twoIter.MoveNext() without checking the value, then access twoIter.Current, or in the second while loop where you access oneIter.Current when you know that oneIter.MoveNext() has returned false.Here's 3 more:
Make the lists the same size, then just simple Select.
(a.Count < b.Count ? a : b).AddRange(new double[Math.Abs(a.Count - b.Count)]);
var c = a.Select((n, i) => n + b[i]);
Don't make them the same size, but go through the longest and check for end of range on the shortest (store shortList.Count for easy perf gain):
var longList = a.Count > b.Count ? a : b;
var shortList = longList == a ? b : a;
var c = longList.Select((n, i) => n + (shortList.Count > i ? shortList[i] : 0));
Take while you can, then Skip and Union the rest:
var c = a.Take(Math.Min(a.Count, b.Count))
.Select((n, i) => n + b[i])
.Union(a.Skip(Math.Min(a.Count, b.Count));
As a combination of the answers from Marc and Damian, you can just use this code, which is a bit more production ready:
public static class EnumerableExtensions
{
public static IEnumerable<T> Merge<T>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, T> operation)
{
return Merge<T, T, T>(first, second, operation);
}
public static IEnumerable<TResult> Merge<T, TResult>(this IEnumerable<T> first, IEnumerable<T> second, Func<T, T, TResult> operation)
{
return Merge<T, T, TResult>(first, second, operation);
}
public static IEnumerable<TResult> Merge<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> operation)
{
if (first == null) throw new ArgumentNullException(nameof(first));
if (second == null) throw new ArgumentNullException(nameof(second));
using (var iter1 = first.GetEnumerator())
using (var iter2 = second.GetEnumerator())
{
while (iter1.MoveNext())
{
yield return iter2.MoveNext()
? operation(iter1.Current, iter2.Current)
: operation(iter1.Current, default);
}
while (iter2.MoveNext())
{
yield return operation(default, iter2.Current);
}
}
}
}
My implementation using a loop:
List<double> shorter, longer;
if (a.Count > b.Count)
{
shorter = b; longer = a
}
else
{
shorter = a; longer = b;
}
List<double> result = new List<double>(longer);
for (int i = 0; i < shorter.Count; ++i)
{
result[i] += shorter[i];
}
Note that this is an addition to my other answer which explains why this cannot be done via LINQ in 3.5. It's just an attempt to provide the shortest and most readable loop-based implementation.