我正在使用 .NET 3.5,并且希望能够从列表中获取第 *
n
* 个项目。我不关心它是使用 lambda 表达式还是 LINQ 来实现。
编辑
看起来这个问题引起了很多争论(这是一件好事,对吧?)。我学到的主要事情是,当您认为自己知道做某事的所有方法(即使如此简单)时,请再想一想!
return list.Where((x, i) => i % nStep == 0);
我知道这是“老派”,但为什么不直接使用带有
stepping = n
的 for 循环呢?
听起来像
IEnumerator<T> GetNth<T>(List<T> list, int n) {
for (int i=0; i<list.Count; i+=n)
yield return list[i]
}
就可以了。我认为没有必要使用 Linq 或 lambda 表达式。
编辑:
做到了
public static class MyListExtensions {
public static IEnumerable<T> GetNth<T>(this List<T> list, int n) {
for (int i=0; i<list.Count; i+=n)
yield return list[i];
}
}
并且您以 LINQish 方式编写
from var element in MyList.GetNth(10) select element;
第二次编辑:
使其更加LINQish
from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];
您可以使用Where重载来将索引与元素一起传递
var everyFourth = list.Where((x,i) => i % 4 == 0);
For 循环
for(int i = 0; i < list.Count; i += n)
//Nth Item..
我认为如果您提供 linq 扩展,您应该能够在最不具体的接口上进行操作,从而在 IEnumerable 上进行操作。当然,如果您追求速度,特别是对于大 N,您可能会为索引访问提供重载。后者消除了迭代大量不需要的数据的需要,并且比Where子句快得多。提供两个重载可以让编译器选择最合适的变体。
public static class LinqExtensions
{
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0)
{
int c = 0;
foreach (var e in list)
{
if (c % n == 0)
yield return e;
c++;
}
}
}
public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0)
for (int c = 0; c < list.Count; c += n)
yield return list[c];
}
}
我不确定是否可以使用 LINQ 表达式来实现,但我知道您可以使用
Where
扩展方法来实现。例如,获取每五个项目:
List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();
这将获得第一项以及从那里开始的每第五项。如果您想从第五项而不是第一项开始,请与 4 进行比较,而不是与 0 进行比较。
恕我直言,没有答案是正确的。所有解都从0开始。但我想要真正的第n个元素
public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
for (int i = n - 1; i < list.Count; i += n)
yield return list[i];
}
@belucha 我喜欢这个,因为客户端代码非常可读,并且编译器选择最有效的实现。我将在此基础上将要求降低到
IReadOnlyList<T>
,并保留该部门以实现高性能 LINQ:
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n) {
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
int i = n;
foreach (var e in list) {
if (++i < n) { //save Division
continue;
}
i = 0;
yield return e;
}
}
public static IEnumerable<T> GetNth<T>(this IReadOnlyList<T> list, int n
, int offset = 0) { //use IReadOnlyList<T>
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
for (var i = offset; i < list.Count; i += n) {
yield return list[i];
}
}