C# 在C语言中求列表的n个元素的最大值#

C# 在C语言中求列表的n个元素的最大值#,c#,linq,max,nested-lists,C#,Linq,Max,Nested Lists,我有一个C#中的列表列表,其中每个子列表有三个双精度,表示一个3D点: {{x1, y1, z1}, {x2, y2, z2}, {x3, y3, z3}} 我想找到这个数据集的三维边界框,这意味着找到最小X,最大X,最小Y,最大Y,等等 使用Python/Numpy,我可以使用,比如说,zmax=list of_list[:,2].max(),等等来获得它 在C#中有没有一种优雅的方法可以做到这一点?我怀疑Linq是一种可行的方法,但我还不了解它是如何工作的(如果一些答案包括Linq,请

我有一个C#中的列表列表,其中每个子列表有三个双精度,表示一个3D点:

{{x1, y1, z1},
 {x2, y2, z2},
 {x3, y3, z3}}
我想找到这个数据集的三维边界框,这意味着找到最小X,最大X,最小Y,最大Y,等等

使用Python/Numpy,我可以使用,比如说,
zmax=list of_list[:,2].max()
,等等来获得它


在C#中有没有一种优雅的方法可以做到这一点?我怀疑Linq是一种可行的方法,但我还不了解它是如何工作的(如果一些答案包括Linq,请解释它是如何工作的,请:o)

您是否查看了SelectMany Linq操作符?我认为这可能对你的问题有帮助。

是的,你可以用C#with LINQ这样做:

var orig = new List<List<double>>();
var maxX = orig.Select(pt => pt[0]).Max();
var maxY = orig.Select(pt => pt[1]).Max();
var maxZ = orig.Select(pt => pt[2]).Max();
var topLeft = new double[] 
{
    list_of_lists.Min(p => p[0]),
    list_of_lists.Min(p => p[1]),
    list_of_lists.Min(p => p[2])
};
var bottomRight = new double[] 
{
    list_of_lists.Max(p => p[0]),
    list_of_lists.Max(p => p[1]),
    list_of_lists.Max(p => p[2])
};
var list = new []
            {
                new [] { 1, 2, 3 },
                new [] { 4, 5, 6 },
                new [] { 7, 8, 9 }
            };
var maxX = list.Select(s => s.Skip(0).Take(1)).Max();
var minY = list.Select(s => s.Skip(1).Take(1)).Min();

如果所有元素的类型相同,并且您感兴趣的属性命名为,例如,
Z
,则可以执行以下操作:

var max = list_of_points.Max(p => p.Z);
var max = list_of_lists.Max(p => p[0]);
在您的情况下,由于您似乎正在使用一个
double[][]
,因此可以执行以下操作:

var max = list_of_points.Max(p => p.Z);
var max = list_of_lists.Max(p => p[0]);
因此,完整边界框将由两点定义,如下所示:

var orig = new List<List<double>>();
var maxX = orig.Select(pt => pt[0]).Max();
var maxY = orig.Select(pt => pt[1]).Max();
var maxZ = orig.Select(pt => pt[2]).Max();
var topLeft = new double[] 
{
    list_of_lists.Min(p => p[0]),
    list_of_lists.Min(p => p[1]),
    list_of_lists.Min(p => p[2])
};
var bottomRight = new double[] 
{
    list_of_lists.Max(p => p[0]),
    list_of_lists.Max(p => p[1]),
    list_of_lists.Max(p => p[2])
};
var list = new []
            {
                new [] { 1, 2, 3 },
                new [] { 4, 5, 6 },
                new [] { 7, 8, 9 }
            };
var maxX = list.Select(s => s.Skip(0).Take(1)).Max();
var minY = list.Select(s => s.Skip(1).Take(1)).Min();
但是,这需要在列表中进行6次传递(每个点的每个坐标对应一次)。您可以这样做来提高性能:

var topLeft = list_of_lists.Aggregate((s, p) => return double[] { Math.Min(s[0], p[0]), Math.Min(s[1], p[1]), Math.Min(s[2], p[2]) });
var bottomRight = list_of_lists.Aggregate((s, p) => return double[] { Math.Max(s[0], p[0]), Math.Max(s[1], p[1]), Math.Max(s[2], p[2]) });
这将使列表只通过2次


注意:
List
而不是
double[][]
可以完成相同的代码,只需在每个数组声明后添加
.ToList()

创建这样的列表,如果需要更多功能,可以为3D点使用特定类,而不是元组

var points = new[] {
    Tuple.Create(x1, y1, z1),
    Tuple.Create(x2, y3, z2),
    Tuple.Create(x3, y3, z3)
};
然后,像@dasblinkenlight写入一样,您可以使用linq选择
Max()
Min()

甚至更短:

var maxX = points.Max(pt => pt.Item1);

编辑:一个易于使用的简单类:

class Point3D {
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }

    public Point3D(double x, double y, double z) {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }
}

var points = new[] {
    new Point3D(x1, y1, z1),
    new Point3D(x2, y3, z2),
    new Point3D(x3, y3, z3)
};

var maxX = points.Max(pt => pt.X);

如果这真的是一个双精度的
IEnumerable
IEnumerables
,X,Y,Z的顺序始终相同,那么您可以这样做:

var orig = new List<List<double>>();
var maxX = orig.Select(pt => pt[0]).Max();
var maxY = orig.Select(pt => pt[1]).Max();
var maxZ = orig.Select(pt => pt[2]).Max();
var topLeft = new double[] 
{
    list_of_lists.Min(p => p[0]),
    list_of_lists.Min(p => p[1]),
    list_of_lists.Min(p => p[2])
};
var bottomRight = new double[] 
{
    list_of_lists.Max(p => p[0]),
    list_of_lists.Max(p => p[1]),
    list_of_lists.Max(p => p[2])
};
var list = new []
            {
                new [] { 1, 2, 3 },
                new [] { 4, 5, 6 },
                new [] { 7, 8, 9 }
            };
var maxX = list.Select(s => s.Skip(0).Take(1)).Max();
var minY = list.Select(s => s.Skip(1).Take(1)).Min();

OP表示他对LINQ不太熟悉-举个例子会有帮助。@SrikanthVenugopalan同意,但提供例子和答案可能会适得其反,因为强迫他查找操作员,他可能会发现其他东西或学到超出我给他的范围的东西。首先,这不是答案。充其量只是一个评论。第二,这几乎肯定没有帮助。他想要每个列的最大值,而将列表展平则会消除确定某个值是代表X、Y还是Z值的能力。除了不同的数据类型(很容易适应我的问题)之外,这似乎就是我想要的。如果答案被编辑,是否应该删除否决票?我相信它应该是
orig.Select(pt=>pt[0]).Max()
,不是吗?@Clint很公平,这已经解决了。(至于第二个解决方案:由于我的列表相对较小,我将使用更紧凑、可读性更强的解决方案,在我的情况下,实际的性能差异可以忽略不计)。无需同时使用
Select
Max
Max
使用一个选择器。@Servy我选择了一个最能模仿OP的
列表[:,2]的解决方案。Max()
示例。虽然
orig.Max(pt=>pt[0])()(
更短,甚至更快,但它隐藏了解决方案的内部工作。已经有
System.Windows.Media.Media3D.Point3D
类(非常隐藏,非常有用……;o)当我把Google放到你的答案中时,我找到了现有的
Point3D
,但决定无论如何写一个,因为它在
PresentationCore.dll中,你不太可能引用它。但不管怎样,在这里提到它还是很好的,谢谢@Xaruth当系统中已经构建了一个类来准确表示对象所表示的内容时,为什么要使用
Tuple
?您获得了改进的类型安全性、基于类型名对其他人更清晰地表示实例的含义、获得了适当的属性名等。
Tuple
有什么优势?我认为
Tuple
对于快速完成一些任务非常有用,但为了属性名的可读性,通常仍然更喜欢使用合适的类。@在这种特殊情况下(3个双倍表示一个点),您可以使用Point3D。但是,一般来说,可以使用Tuple做更多的工作,因为它不限于3个元素和双类型。如果问题是“i have n element of type x”,则元组解决方案仍然很好。此答案假设这是一个点对象列表,op似乎使用三个坐标的列表作为他的点对象。@DeniseSkidmore与这里回答的大多数人一样,我最初误解了op的问题。我更新了我的答案,使之更适用。