我有一个多维数组 ins C#,定义如下:
double[,,] myArray=new double[10000,10000,3];
例如,当最后一个暗淡为 0 时,我找到了该数组的最大值。诸如此类的 g:
double m1=myArray[?,?,0].Max();
如何使用 Linq 或其他方法计算它?
我有一个多维数组 ins C#,定义如下:
double[,,] myArray=new double[10000,10000,3];
例如,当最后一个暗淡为 0 时,我找到了该数组的最大值。诸如此类的 g:
double m1=myArray[?,?,0].Max();
如何使用 Linq 或其他方法计算它?
如果您想获得数组的某个子集的最大值,您可以这样做:
double m1 =
(from x in Enumerable.Range(0, myArray.GetLength(0))
from y in Enumerable.Range(0, myArray.GetLength(1))
select myArray[x, y, 0])
.Max();
如果您想获得数组中所有元素的最大值,您可以这样做
double m1 = myArray.Cast<double>().Max();
但是,您可以通过实现自己的扩展方法来获得显着的性能提升,如下所示:
public static IEnumerable<T> Flatten<T>(this T[,,] arry) {
foreach(T x in arry) yield return item;
}
myArray.Flatten().Max();
编辑 2
请注意,此扩展同样适用于基于非零的数组的可怕但有效的情况,
var nonZeroBasedArray = Array.CreateInstance(
typeof(double),
new[] { 4, 4, 3 },
new[] { -2, -2, 0 });
请注意,前两个维度的范围从-2
到1
包含(yikes)。此测试代码说明Flatten
扩展仍然有效。
var count = 0;
foreach (var element in nonZeroBasedArray.Flatten<double>(null, null, 0))
{
Console.Write(string.Join(", ", element.Key));
Console.WriteLine(": {0}", element.Value);
}
Console.WriteLine("Count: {0}", count);
Console.ReadKey();
编辑
所以,使用下面定义的扩展你可以做
var myArray = new double[10000,10000,3];
var ordered = myArray.Flatten<double>(null, null, 0).OrderBy(p => p.Value);
var maxZ0 = ordered.First();
var minZ0 = ordered.Last();
元素类型是 aKeyValuePair<IEnumerable<int>, T>
因此Key
允许您反向引用原始数组。
好的,这是一个通用扩展,最初是受pswg 回答的启发
如果你从Eric Lippert 的励志CartesianProduct<T>
扩展开始,
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[]
{
item
}));
}
然后,您创建一个函数来生成多维数组的绑定集,该数组允许您为某些维度指定固定值。
private static IEnumerable<IEnumerable<int>> GetBoundSequences(
Array array,
int?[] definedBounds)
{
for (var rank = 0; rank < array.Rank; rank++)
{
var defined = definedBounds.ElementAtorDefault(rank);
if (defined.HasValue)
{
yield return new[] { defined.Value };
}
else
{
var min = array.GetLowerBound(rank);
yield return Enumerable.Range(
min,
(array.GetUpperBound(rank) - min) + 1);
}
}
}
您可以使用两者来进行灵活的Flatten<T>
扩展,适用于任何等级的数组。
public static IEnumerable<KeyValuePair<IEnumerable<int>, T>> Flatten<T>(
this Array array,
params int?[] definedBounds)
{
var coordSets = GetBoundSequences(array, definedBounds).CartesianProduct();
foreach (var coordSet in coordSets)
{
var coords = coordSet.ToArray();
var value = (T)array.GetValue(coords);
yield return new KeyValuePair<IEnumerable<int>, T>(
coords,
value);
}
}
一旦你有了这个,你可以做类似的事情
var myArray = new double[10000,10000,3];
var maxZ0 = myArray.Flatten<double>(null, null, 0).Max(p => p.Value);
这很好,因为它只懒惰地迭代和转换指定的元素。
尝试这个
double[,,] myArray = new double[10000, 10000, 3];
double max = myArray.Cast<double>().Max();