Bill Blogs in C#

Bill Wagner discusses C#, LINQ, and other items of interest

A Functional Programming Q & A

I received this question in email from one of my readers, and I thought it would be of general interest:

I find myself with two arrays of the same size and I want to create a third that combines

each element. What I want is something similar to

var S3 = S1.foreach(S2, (s1, s2) => s1 + s2);

this would give S3[i] = S1[i] + S2[i]; for all i

Since this is a common pattern, I was wondering if you know what is a good functional solution.

Thank you for any input you would have

I wrote a couple methods that makes this rather quite simple.  First, I wrote an extension method that merges two sequence:

   1: public static IEnumerable<T> Merge<T>(this IEnumerable<T> leftSequence, 
   2:     IEnumerable<T> rightSequence,
   3:     Func<T, T, T> mergeFunc)
   4: {
   5:     IEnumerator<T> leftEnumerator = leftSequence.GetEnumerator();
   6:     IEnumerator<T> rightEnumerator = rightSequence.GetEnumerator();
   7:     while (leftEnumerator.MoveNext() && rightEnumerator.MoveNext())
   8:     {
   9:         yield return mergeFunc(leftEnumerator.Current, rightEnumerator.Current);
  10:     }
  11: }

 

Once that's done, it provides almost exactly the syntax you requested:

   1: int[] leftVector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
   2: int[] rightVector = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
   3:  
   4: var sum = leftVector.Merge(rightVector, (x, y) => x + y).ToArray();
   5:  
   6: foreach (var value in sum)
   7:     Console.WriteLine(value);

 

There are a few caveats here.  This doesn't test for any errors if the two vectors aren't the same length. That may or may not matter for you. I like this idiom, because you can do other operations on sequences as well.  Here's multiply:

   1: var sum = leftVector.Merge(rightVector, (x, y) => x * y).ToArray();

I hope that helps.

Published Wednesday, April 23, 2008 10:00 PM by wwagner

Comments

# re: A Functional Programming Q & A@ Monday, April 28, 2008 11:25 AM

Since IEnumerator<T> implements IDisposable, it's probably a good practice to declare leftEnumerator and rightEnumerator inside using statements.

# re: A Functional Programming Q & A@ Tuesday, April 29, 2008 3:45 PM

In Scala, you could do:

val leftVector = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

val rightVector = Array(9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

val answer =

  for ((v1, v2) <- leftVector zip rightVector)

    yield v1 + v2

Likewise, the multiply just changes the yield statement to yield v1 * v2

by Dianne Marsh