[英]Confused on c# lambda expression with Linq
我試圖理解這部分代碼:
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 表達式示例。 看完這些例子后,我仍然停留在這些代碼上。
正如我在評論中所說的那樣,這段代碼本身就太“聰明”了,而且由於重復迭代而非常非常慢。
前兩個查詢是多余的,因為最后, leafIndexes
只包含color
255 的索引,或者更確切地說, 0x0000FF
。 Select((item,index)=>...)
經過項目及其索引拉姆達。 這兩個查詢可能只是:
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 的 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
. Without it, every time
triplet or
leafIndexes` 時,查詢都會再次執行。
這段代碼沒有做的一件事是將點放入HashSet
。 此類用於快速、基於集合的就地操作。 如果triplet
是一個 HashSet,調用IntersectWith
將修改它並只留下在leafIndexes
找到的數字。
我不是 C# 專家,但正如我在 microsoft docs 的示例中所見
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)
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 })
它會做完全相同的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.