簡體   English   中英

對使用 Linq 的 c# lambda 表達式感到困惑

[英]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 並且intColor32都沒有屬性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)

例如。 如果你稱它為coloritem或其他任何東西,這完全取決於你!

老實說,我不知道,但顯然您可以在需要時包含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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM