【问题标题】:C# equivalent of Julia's map!() methodC# 相当于 Julia 的 map!() 方法
【发布时间】:2020-07-17 11:52:10
【问题描述】:

我正在尝试找到与 Julia 的 map!() 方法等效的 C# 方法,该方法的返回类型为 void,并接受一个函数、一个目标和一个函数所作用的集合。

我能找到的最好的东西是 C# 的 Enumerable.Select(),它将函数作为第三个参数,将集合作为第一个参数。但是,它返回一个新集合,而不是修改“目标”中的集合。这类似于 Julia 的 map() 更多。

【问题讨论】:

  • .Select() 是一种LINQ扩展方法,它是一个查询,不按约定改变源。您必须分配结果或执行.ToList().ForEach(x => ....);
  • @FalcoAlexander ToList().ForEach 是可憎的。如果您需要迭代查询,只需执行foreach(var x in query) 而不是迭代查询以创建中间列表,然后迭代列表并将其丢弃。
  • 你是对的,同意!!
  • 最终,与其尝试重新创建 Julia 在 C# 中的工作方式,不如只学习如何编写 C# 工作方式的代码。在这种情况下,destination = source.Select(func).ToList(); 似乎是您想要的。这实际上比map!() 更好,因为您不需要预先创建集合或确保它足够大,我认为这两件事会导致各种错误。
  • 拥有变异映射函数的原因是,出于性能原因,您可能希望重用已分配的内存。如果在热循环的每次迭代中分配一个新的输出数组可能会很浪费。非变异映射只是 Julia 中的 map

标签: c# julia equivalent


【解决方案1】:

没有像这样的标准,但您可以轻松地将自己的扩展方法添加到IEnumerable 以添加此功能。例如:

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++;
    }
}

怎么说呢:

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

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

注意:我省略了任何错误处理。例如,您需要确保目标列表足够长以获取插入的值。

【讨论】:

  • 感谢您的回答。我会等待一段时间再接受。
【解决方案2】:

LINQ 中的所有内容在设计上都意味着永远不会修改底层集合,并始终创建一个新的枚举,然后通常使用该枚举来实例化一个新的集合。

你可以写一个这样的辅助函数来实现你想要的:

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++;
    }
}

用法如下:

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 + " ");
}

结果:3 4 5 6

由于我们在方法的签名中使用了IList&lt;T&gt;,所以目的地也可以是一个数组,它可以正常工作:

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 + " ");
    }
}

它利用了这样一个事实,即在您调用类似ToArray()ToList() 之前,LINQ 尚未实例化新集合,它只是在源集合中的元素上进行惰性迭代。所以不要调用ToArray()ToList(),遍历生成的IEnumerable&lt;TResult&gt; 并将其分配给目的地。请注意,如果您担心的话,可能还有更友好的方式来执行此操作。

就像 Julia 的 map 方法一样,这仅在目标集合至少一样大时才有效。

【讨论】:

  • 感谢您的回答。我会等待一段时间再接受。
猜你喜欢
  • 2018-06-24
  • 2021-09-14
  • 2019-02-05
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-06
  • 1970-01-01
相关资源
最近更新 更多