簡體   English   中英

如何從列表中選擇每個第6個元素(使用Linq)

[英]How do I select every 6th element from a list (using Linq)

我有一個'雙'值列表。 我需要選擇每第6條記錄。 這是一個坐標列表,我需要獲得每第6個值的最小值和最大值。

坐標列表(樣本): [2.1, 4.3, 1.0, 7.1, 10.6, 39.23, 0.5, ... ] 2.1,4.3,1.0,7.1,10.6,39.23,0.5 [2.1, 4.3, 1.0, 7.1, 10.6, 39.23, 0.5, ... ]帶有坐標的坐標。

結果應如下所示: [x_min, y_min, z_min, x_max, y_max, z_max] ,正好有6個坐標。

以下代碼有效,但需要很長時間才能遍歷所有坐標。 我想用Linq代替(也許更快?)

for (int i = 0; i < 6; i++)
{
    List<double> coordinateRange = new List<double>();

    for (int j = i; j < allCoordinates.Count(); j = j + 6)
        coordinateRange.Add(allCoordinates[j]);

    if (i < 3) boundingBox.Add(coordinateRange.Min());
    else boundingBox.Add(coordinateRange.Max());
}

有什么建議? 非常感謝! 映入眼簾!

coordinateRange.Where( ( coordinate, index ) => (index + 1) % 6 == 0 );

Webleeuw的答案在此之前發布,但恕我直言,使用索引作為參數而不是使用IndexOf方法更清楚。

這樣的事可以幫助:

public static IEnumerable<T> Every<T>(this IEnumerable<T> source, int count)
{
    int cnt = 0;
    foreach(T item in source)
    {
        cnt++;
        if (cnt == count)
        {
            cnt = 0;
            yield return item;
        }
    }
}

你可以像這樣使用它:

    int[] list = new []{1,2,3,4,5,6,7,8,9,10,11,12,13};
    foreach(int i in list.Every(3))
        { Console.WriteLine(i); }

編輯

如果要跳過前幾個條目,可以使用Skip()擴展方法:

foreach (int i in list.Skip(2).Every(6))
{ Console.WriteLine(i); }

Where方法的重載使您可以直接使用索引:

coordinateRange.Where((c,i) => (i + 1) % 6 == 0);

您想使用LINQ執行此操作的任何特定原因?

為什么不編寫一個循環,每次以6個增量步進並直接訪問該值?

要找到更快的解決方案,請啟動配置文件

測量for循環中每個步驟所需的時間,並盡量避免最大的瓶頸。

看了你的代碼之后,你的問題就是你在大清單上運行了六次。 所以所需的時間總是列表大小的六倍。

相反,您應該在整個列表上運行一次,並將每個項目放入正確的插槽中。

只是為自己做一個性能測試,你應該測試這兩種方法:

用於保存數據的示例類

public class Coordinates
{
    public double x1 { get; set; }
    public double x2 { get; set; }

    public double y1 { get; set; }
    public double y2 { get; set; }

    public double z1 { get; set; }
    public double z2 { get; set; }
}

初始化價值持有人

Coordinates minCoordinates = new Coordinates();

//Cause we want to hold the minimum value, it will be initialized with
//value that is definitely greater or equal than the greatest in the list
minCoordinates.x1 = Double.MaxValue;
minCoordinates.x2 = Double.MaxValue;
minCoordinates.y1 = Double.MaxValue;
minCoordinates.y2 = Double.MaxValue;
minCoordinates.z1 = Double.MaxValue;
minCoordinates.z2 = Double.MaxValue;

如果索引運算符為O(1),則使用for循環

for (int i = 0; i < allCoordinates.Count; i++)
{
    switch (i % 6)
    {
        case 0:
            minCoordinates.x1 = Math.Min(minCoordinates.x1, allCoordinates[i]);
            break;
        case 1:
            minCoordinates.x2 = Math.Min(minCoordinates.x2, allCoordinates[i]);
            break;
        case 2:
            minCoordinates.y1 = Math.Min(minCoordinates.y1, allCoordinates[i]);
            break;
        case 3:
            minCoordinates.y2 = Math.Min(minCoordinates.y2, allCoordinates[i]);
            break;
        case 4:
            minCoordinates.z1 = Math.Min(minCoordinates.z1, allCoordinates[i]);
            break;
        case 5:
            minCoordinates.z2 = Math.Min(minCoordinates.z2, allCoordinates[i]);
            break;
    }
}

如果IEnumerator為O(1),則使用foreach

int count = 0;
foreach (var item in allCoordinates)
{
    switch (count % 6)
    {
        case 0:
            minCoordinates.x1 = Math.Min(minCoordinates.x1, item);
            break;
        case 1:
            minCoordinates.x2 = Math.Min(minCoordinates.x2, item);
            break;
        case 2:
            minCoordinates.y1 = Math.Min(minCoordinates.y1, item);
            break;
        case 3:
            minCoordinates.y2 = Math.Min(minCoordinates.y2, item);
            break;
        case 4:
            minCoordinates.z1 = Math.Min(minCoordinates.z1, item);
            break;
        case 5:
            minCoordinates.z2 = Math.Min(minCoordinates.z2, item);
            break;
    }
    count++;
}

好吧,它不是LINQ,但如果你擔心性能,這可能會有所幫助。

public static class ListExtensions
{
    public static IEnumerable<T> Every<T>(this IList<T> list, int stepSize, int startIndex)
    {
        if (stepSize <= 0)
            throw new ArgumentException();

        for (int i = startIndex; i < list.Count; i += stepSize)
            yield return list[i];
    }
}

建議:

coordinateRange.Where(c =>(coordinateRange.IndexOf(c)+ 1)%6 == 0);

我的立場得到了糾正,感謝您的評論。 正如codymanix所說,正確的答案確實是:

coordinateRange.Where((c, i) => (i + 1) % 6 == 0);

執行此操作的最佳方法是重構數據結構,以便每個維度都是自己的數組。 那樣x1_max就是x1.Max() 如果您無法更改輸入數據結構,則下一個最佳方法是迭代數組一次並在本地執行所有訪問。 這有助於保留在L1緩存內存中:

var minValues = new double[] { Double.MaxValue, Double.MaxValue, Double.MaxValue };
var maxValues = new double[] { Double.MinValue, Double.MinValue, Double.MinValue };

for (int i = 0; i < allCoordinates.Length; i += 6) 
{
    for (int j = 0; i < 3; i++)
    {
        if (allCoordinates[i+j] < minValues[j])
            minValues[j] = allCoordinates[i+j];
        if (allCoordinates[i+j+3] > maxValues[j])
            maxValues[j] = allCoordinates[i+j+3];
    }
}

使用Skip和combintaion與Take。

coordinateRange.Skip(6).Take(1).First();

我建議您將其移至擴展方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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