1

我正在使用NumSharp并且对它有点陌生。我想设置多个数据值,主要关注两个功能:

NDArray.SetValue(object value, param int[] indices)
NDArray.SetData(object value, param int[] indices)

第一个SetValue期望单个值元素的完整索引,例如,如果您拥有np.zeros(3,3)它期望完整索引,并且如果缺少索引,它将使用0它的位置。

例如:

var arr = np.zeros(3,3);
arr.SetValue(10.0, 0); 
arr.SetValue(10.0, 0, 0); 

两条线是等价的。

另一方面,SetData将根据索引修改整个子数组,如果给出完整索引,它的工作方式类似于SetValue. 例如:

arr.SetData(10.0, 0); // sets all arr[0] values to 10
arr.SetData(10.0, 0, 1); // sets arr[0][1] to 10

现在,对于我的用例,我想重新定义一个接受多个值并将每个值视为子数组索引的函数。

arr.SetMultiData(10.0, 0, 1); /// sets arr[0] and arr[10] values to 10

自然,我选择了一种扩展方法:

public static class Extensions
{
    public static void SetMultiData(this NDArray arr, object value, int[] indices)
    {
        foreach (var i in indices)
            arr.SetData(value, i);
    }
}

但这就是完全失去我的地方。此代码不使用扩展方法,有效:

    static void Main(string[] args)
    {
        NDArray arr = np.zeros(3, 3);
        int[] indices = new int[] { 0, 1 };
        double value = 10;

        foreach (var i in indices)
            arr.SetData(value, i); 

        Console.WriteLine(arr.ToString());
    }

输出:

[[10, 10, 10],[10, 10, 10],[0, 0, 0]]

此代码不会:

    static void Main(string[] args)
    {
        NDArray arr = np.zeros(3, 3);
        int[] indices = new int[] { 0, 1 };
        double value = 10;

        arr.SetMultiData(value, indices);

        Console.WriteLine(arr.ToString());
    }

输出:

[[10, 0, 0],[0, 0, 0],[0, 0, 0]]

这并不总是会打印,在大多数情况下它只是无法打印,我相信底层arr结构已相应损坏,当我多次运行它时会导致未定义的行为。

现在,最后一点。当我将Extension方法更改为 acceptdouble而不是 时object,它可以完美运行。但是我需要扩展方法来处理多种类型,因为它只是SetData. 鉴于此,我还尝试将方法更改为通用:

public static class Extensions
{
    public static void SetMultiData<T>(this NDArray arr, object value, int[] indices)
    {
        T val = (T)value;
        foreach (var i in indices)
            arr.SetData(val, i);
    }
}

当这不起作用并产生相同的输出时,我感到震惊。基本上,我进行了从对象到类型的显式转换。我这样调用函数:我使用调试器并比较了与它一起工作的代码,类型与传递给给定andarr.SetMultiData<double>(value, indicies);的类型完全相同,但一个有效,一个无效。arr.SetValuei = intval = double

是什么导致了这种行为?为什么当我明确地将它设置为double使用泛型/object类型都失败时它会起作用?

作为参考,这里是SetData实现。这是开源的。

4

1 回答 1

1

原因是double可以隐式转换为NDArray(通过 中定义的隐式运算符NDArray)。所以当你这样做时:

arr.SetData(value, i);

andvalue是类型double- 被调用的重载 is SetData(NDArray, int[),因为它是最适合的,double可以转换为NDArray.

然而,当valueis 类型object甚至是未解析的泛型类型 ( T) - 然后调用重载 is SetData(object, int[]),所以事情变得疯狂(因为如果你作为对象传递的值不是 NDArray,那么这些重载会做完全不同的事情,而且它不是 - 它是双重的) . 重载是在编译时选择的,即使在泛型情况下,编译器也无法选择NDArray重载(因为选择的重载应该适合您可以传递的任何可能的泛型类型)。

在您的情况下,您可以通过NDArray value在扩展方法中使用而不是对象或泛型来“解决”这个问题:

public static class Extensions
{
    public static void SetMultiData(this NDArray arr, NDArray value, int[] indices)
    {
        foreach (var i in indices)
            arr.SetData(value, i);
    }
}
于 2021-09-23T12:34:27.983 回答