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
obvisouly 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
obvisouly 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;
}
}
}
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'
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];
}
The ugly LINQ solution:
var sum = Enumerable.Range(0, (a.Count > b.Count) ? a.Count : b.Count)
.Select(i => (a.Count > i && b.Count > i) ? a[i] + b[i] : (a.Count > i) ? a[i] : b[i]);
Enumerable.Range(0, new[] { a.Count, b.Count }.Max())
.Select(n => a.ElementAtOrDefault(n) + b.ElementAtOrDefault(n));
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();
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));