Search code examples
c#listperformancelinqgenerics

element-wise add / subtract / multiply / divide operation in two lists in C#


Considering element-wise add / subtract / multiply / divide operation in two lists. I have the code as follows.

public class Calculate
{
    public static IEnumerable<T> Add<T>(IEnumerable<T> input1, IEnumerable<T> input2)
    {
        return input1.Zip(input2, (first, second) => (dynamic)first + (dynamic)second).Cast<T>();
    }

    public static IEnumerable<T> Subtract<T>(IEnumerable<T> input1, IEnumerable<T> input2)
    {
        return input1.Zip(input2, (first, second) => (dynamic)first - (dynamic)second).Cast<T>();
    }

    public static IEnumerable<T> Multiply<T>(IEnumerable<T> input1, IEnumerable<T> input2)
    {
        return input1.Zip(input2, (first, second) => (dynamic)first * (dynamic)second).Cast<T>();
    }

    public static IEnumerable<T> Divide<T>(IEnumerable<T> input1, IEnumerable<T> input2)
    {
        return input1.Zip(input2, (first, second) => (dynamic)first / (dynamic)second).Cast<T>();
    }

}

Tests

List<double> doubles = new List<double>();
for (int i = 0; i < 10; i++)
{
    doubles.Add((double)i);
}
foreach (var element in Calculate.Add(doubles, doubles))
{
    Console.WriteLine(element.ToString());
}

It just works, but dealing with dynamic, I am wondering if it is the right way to do it? Is the code generic enough?


Solution

  • I suggest using generic math here, e.g.

    using System.Numerics;
    
    ...
    
    public static IEnumerable<T> Add<T>(IEnumerable<T> input1, IEnumerable<T> input2) 
      where T : IAdditionOperators<T, T, T> {
    
      ArgumentNullException.ThrowIfNull(input1);
      ArgumentNullException.ThrowIfNull(input2);
    
      return input1.Zip(input2, (first, second) => first + second);
    }
    

    We can implement all the rest operations in the similar way:

    public static IEnumerable<T> Subtract<T>(IEnumerable<T> input1, IEnumerable<T> input2) 
      where T : ISubtractionOperators<T, T, T> {
    
      ArgumentNullException.ThrowIfNull(input1);
      ArgumentNullException.ThrowIfNull(input2);
    
      return input1.Zip(input2, (first, second) => first - second);
    }
    
    public static IEnumerable<T> Multiply<T>(IEnumerable<T> input1, IEnumerable<T> input2) 
      where T : IMultiplyOperators<T, T, T> {
    
      ArgumentNullException.ThrowIfNull(input1);
      ArgumentNullException.ThrowIfNull(input2);
    
      return input1.Zip(input2, (first, second) => first * second);
    }
    
    public static IEnumerable<T> Divide<T>(IEnumerable<T> input1, IEnumerable<T> input2) 
      where T : IDivisionOperators<T, T, T> {
    
      ArgumentNullException.ThrowIfNull(input1);
      ArgumentNullException.ThrowIfNull(input2);
    
      return input1.Zip(input2, (first, second) => first / second);
    }