C# equivalent of Julia's map!() method

Viewed 111

I'm trying to find C#'s equivalent of Julia's map!() method, which is of void return type and takes a function, a destination and a collection on which the function acts.

The best thing that I could find is C#'s Enumerable.Select(), which takes the function as the third argument, and the collection as the first argument. However, it returns a new collection instead of modifying the one in the "destination". That resembles Julia's map() more.

2 Answers

There's nothing as standard like this, but you can easily add your own extension method to IEnumerable to add this functionality. For example:

public static void JuliaMap<TFrom, TTo>
(
    this IEnumerable<TFrom> source, 
    IList<TTo> target, 
    Func<TFrom, TTo> selector
)
{
    var next = 0;
    foreach(var value in source)
    {
        var convertedValue = selector(value);
        target[next] = convertedValue;
        next++;
    }
}

How you can say:

var numbers = new[]{1, 2, 3};
var target = new string[3];

numbers.JuliaMap(target, i => (i * 2).ToString());

NOTE: I've left out any error handling. For example, you'll want to make sure that the target list is long enough to take the inserted value.

Everything in LINQ is by design meant to never modify the underlying collection and to always create a new enumeration that is generally then used to instantiate a new collection.

You can write a helper function like this to achieve what you want:

public static void SelectToDestination<TSource, TResult>(
    Func<TSource, TResult> selector, 
    IEnumerable<TSource> source, 
    IList<TResult> destination)
{
    int i = 0;
    foreach (var item in source.Select(selector))
    {
        destination[i] = item;
        i++;
    }
}

Usage looks like this:

var l1 = new List<int>() { 1, 2, 3, 4 };
var l2 = new List<int>() { 0, 0, 0, 0 };
SelectToDestination(x => x + 2, l1, l2);

foreach(var item in l2)
{
    Console.Write(item + " ");
}

Results in: 3 4 5 6

Since we're using IList<T> in the method's signature, the destination can be an array too and it will work fine:

public static void Main(string[] args)
{
    var l1 = new List<int>() { 1, 2, 3, 4 };
    var l2 = new int[4];
    SelectToDestination(x => x + 2, l1, l2);

    foreach(var item in l2)
    {
        Console.Write(item + " ");
    }
}

It takes advantage of the fact that until you call something like ToArray() or ToList(), LINQ hasn't yet instantiated a new collection, it's just iterating lazily over elements in the source collection. So just don't call ToArray() or ToList(), iterate over the resulting IEnumerable<TResult> and assign it to destination. Note that there are probably more perf friendly ways of doing this if that's a concern for you.

Just like Julia's map method, this will only work if the destination collection is at least as big.

Related