我试图理解这部分代码:
int[] triangles = mesh.triangles;
Color32[] colors = mesh.colors32;
IEnumerable<IGrouping<byte, int>> hierarchyMap = colors
.Select((color, index) => new { color, index })
.GroupBy(c => c.color.g, c => c.index);
IEnumerable<int> leafIndexes = hierarchyMap
.Where(x => x.Key == 255)
.SelectMany(x=>x);
Dictionary<int, HashSet<int>> faces = triangles
.Select((vert, index) => new { vert, index })
.GroupBy(g => g.index / 3, i => i.vert)
.Where(g=> leafIndexes.Any(leaf=>g.Contains(leaf)))
.ToDictionary(g=>g.Key, g=>new HashSet<int>(g));
这些代码对我来说就像魔术。似乎“ c”代表颜色中的每个元素,类型Color32
确实具有一个名为color
的属性。但是在最后一行,triangle
是类型int
的数组,int
类型如何具有称为vert
的属性?并且int
和Color32
都没有属性index
。
我对这些表达式很困惑,我只在网上找到一些简单的Lambda表达式示例。阅读示例后,我仍然停留在这些代码上。
答案 0 :(得分:1)
正如我在评论中说的那样,此代码本身就太“聪明”了,由于重复的迭代,它非常非常慢。
前两个查询是多余的,最后,leafIndexes
仅包含索引color
255,或更确切地说是0x0000FF
。 Select((item,index)=>...)
将项目及其的索引传递给lambda。那两个查询可能只是:
var leafIndexes=colors.Select((color,idx)=>{color,idx})
.Where(color=>color=255)
.Select(pair=>pair.idx)
.ToList();
或者,使用迭代器功能:
IEnumerable<int> ColorIndexes(IEnumerable<Color32> colors,int color)
{
int i=0;
foreach(var c in colors)
{
if(c==color) yield return i;
i++;
}
}
...
var leafIndexes=ColorIndexes(colors,255).ToList();
最终查询尝试将顶点成三份批处理。迭代器方法也可以在这里提供帮助,但是更好的主意是使用MoreLINQ's Batch运算符:
int[] vertices= mesh.triangles;
var triangles=vertices.Batch(3);
此后,查询将尝试查找leafIndexes列表中包含哪些“三角形”值。每个“三角形”都是数字列表。我们可以这样写:
var finalTriangles=triangles.Where(points=> points.Any(point=>leafIndexes.Contains(point));
试图查找叶子索引中是否包含任何三角形点。或者我们可以使用Enumerable.Intersect来查看两个数组是否有任何共同的值:
var finalTriangles=vertices.Batch(3)
.Where(points=> points.Intersect(leafIndexes).Any());
查询的最后一步将创建一个字典,该字典具有匹配的“三角形”,其关键字为“三角形”索引。同样,这是Select((item,index))
的工作:
int[] vertices= mesh.triangles;
var finalTriangles=vertices.Batch(3)
.Select((triplet,idx)=>{ triplet=triplet.ToList(),
idx})
.Where(pair=> pair.triplet.Intersect(leafIndexes).Any())
.ToDictionary(pair=>pair.idx,
pair=>pair.triplet);
代码仅使用ToList()
执行一次可枚举,然后返回使用List . Without it, every time
triplet or
leafIndexes`,查询将再次执行。
此代码不所做的一件事是将这些点放入HashSet
中。此类适用于基于集合的快速就地操作。如果triplet
是HashSet,则调用IntersectWith
会对其进行修改,只保留在leafIndexes
中找到的数字。
答案 1 :(得分:0)
我不是C#专家,但正如我在Microsoft文档的示例中所见
https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select?view=netframework-4.8
Select有对象及其索引,因此VERT只是三角形元素之一,而INDEX就是它的索引。我的意思是它是数组中的索引,例如三角形数组[Triangle1,Triangle2,Triangle3]的(object,index)对为(Triangle1,0),(Triangle2,1),(Triangle3,2)
答案 2 :(得分:0)
int类型如何具有称为vert的属性?而且int和Color32都没有属性索引。
您在这里感到困惑:这些不是“属性”,而是迭代变量。
Linq基本上一直都是
的快捷方式foreach(var color in colors)
例如。如果您将其称为color
或item
或其他任何东西,完全取决于您!
老实说,我不知道,但是显然index
可以在需要时包括在内。它是您在使用Linq的列表/ IEnumerable中相应元素的索引。
因此,在GroupBy
中,您实际上可以再次将其称为color
而不是c
。
在以后的vert
中也不是属性,而只是当前项目的名称..您也可以使用
Dictionary<int, HashSet<int>> faces = triangles
.Select((v, i) => new { v, i })
它会做完全一样的事情。