如何将此map-reduce javascript函数呈现为等效的c#LINQ Select-Aggregate语法?
/**
* Multiply transforms into one.
*
* @param {Array} input transforms array
* @return {Array} output matrix array
*/
exports.transformsMultiply = function(transforms) {
// convert transforms objects to the matrices
transforms = transforms.map(function(transform) {
if (transform.name === 'matrix') {
return transform.data;
}
return transformToMatrix(transform);
});
// multiply all matrices into one
transforms = {
name: 'matrix',
data: transforms.reduce(function(a, b) {
return multiplyTransformMatrices(a, b);
})
};
return transforms;
};
答案 0 :(得分:2)
直接等价物看起来像这样:
public Transform TransformsMultiply(IEnumerable<Transform> transforms)
{
var matrices = transforms.Select(transform =>
transform.Name == "matrix"
? transform.Data
: transformToMatrix(transform));
return new Transform
{
Name = "matrix",
Data = matrices.Aggregate((a, b) =>
multiplyTransformMatrices(a, b));
};
}
当然,您需要定义Transform
类以及transformToMatrix
和multiplyTransformMatrices
方法;
虽然通过Name
属性区分变换类型不是惯用的C#。如果为每种类型的转换创建抽象基类Transform
类型和子类会更好:
public abstract class Transform { /* ... */ }
public class Matrix : Transform
{
public int[,] Data { get; set; }
}
public class OtherTypeOfTransform : Transform
{
/* ... */
}
该方法的第一部分如下:
var matrices = transforms.Select(transform =>
transform is Matrix
? transform.Data
: transformToMatrix(transform));
但这不是面向对象的,因为transformToMatrix
需要知道如何将每种类型的转换转换为矩阵。您应该考虑向基类添加一个抽象ToMatrix
方法并在子类中实现它,从而将自身转换为矩阵的责任委托给每个子类。
public abstract class Transform
{
public abstract Matrix ToMatrix();
}
public class Matrix : Transform
{
public int[,] Data { get; set; }
public Matrix ToMatrix() { return this; }
}
public class OtherTypeOfTransform : Transform
{
public Matrix ToMatrix()
{
// Type-specific implementation
}
}
之后,实现将如下所示:
public Matrix TransformsMultiply(IEnumerable<Transform> transforms)
{
return new Matrix
{
Data = transforms
.Select(transform => transform.ToMatrix())
.Aggregate((a, b) => multiplyTransformMatrices(a, b));
};
}
将乘法移动到Matrix
类会使这更好:
public Matrix TransformsMultiply(IEnumerable<Transform> transforms)
{
return new Matrix
{
Data = transforms
.Select(transform => transform.ToMatrix())
.Aggregate((a, b) => a.MultiplyBy(b));
};
}
这就是我将JavaScript转换为惯用的面向对象的C#代码的方法。
修改强>
您问我将如何使用Dictionary<string, decimal[]>
代替IEnumerable<Transform>
来实现这一点,所以这里是:
public KeyValuePair<string, decimal[]> TransformsMultiply(
Dictionary<string, decimal[]> transforms)
{
var matrices = transforms.Select(kvp =>
kvp.Key == "matrix"
? kvp.Value
: transformToMatrix(kvg.Value));
return new KeyValuePair<string, int>(
"matrix",
matrices.Aggregate((a, b) => multiplyTransformMatrices(a, b));
}
Dictionary<TKey, TValue>
是IEnumerable<KeyValuePair<TKey, TValue>>
,因此在此解决方案中,变换由KeyValuePair<string, decimal[]>
表示。
请注意,字典键是唯一的,因此您只能使用键"matrix"
进行一次转换。我不确定这是不是你想要的。
此解决方案的缺点是:
transformToMatrix
和multiplyTransformMatrices
内方法。如果您确实需要变换的通用容器而不是命名类,则可以使用Tuple<T, U>
:
public Tuple<string, decimal[]> TransformsMultiply(
IEnumerable<Tuple<string, decimal[]>> transforms)
{
var matrices = transforms.Select(t =>
t.Item1 == "matrix" ? t.Item2 : transformToMatrix(t.Item2));
return new Tuple<string, decimal[]>(
"matrix",
matrices.Aggregate((a, b) => multiplyTransformMatrices(a, b)));
}
在这里你可以有多个同名的变换,但上面提到的第二个和第三个缺点仍然适用。