如何使用LINQ获取序列中除最后一个元素之外的所有元素?

20 浏览
0 Comments

如何使用LINQ获取序列中除最后一个元素之外的所有元素?

假设我有一个序列。

IEnumerable sequence = GetSequenceFromExpensiveSource();
// sequence now contains: 0,1,2,3,...,999999,1000000

获取序列的成本很高,而且是动态生成的,我想只迭代一次。

我想获取0-999999(即除了最后一个元素之外的所有内容)

我知道我可以做类似以下操作:

sequence.Take(sequence.Count() - 1);

但这会导致两个枚举器遍历大序列。

是否有LINQ构造使我这样做:

sequence.TakeAllButTheLastElement();

admin 更改状态以发布 2023年5月22日
0
0 Comments

我不知道Linq解决方案 - 但是你可以使用生成器(yield return)很容易地编写算法。

public static IEnumerable TakeAllButLast(this IEnumerable source) {
    var it = source.GetEnumerator();
    bool hasRemainingItems = false;
    bool isFirst = true;
    T item = default(T);
    do {
        hasRemainingItems = it.MoveNext();
        if (hasRemainingItems) {
            if (!isFirst) yield return item;
            item = it.Current;
            isFirst = false;
        }
    } while (hasRemainingItems);
}
static void Main(string[] args) {
    var Seq = Enumerable.Range(1, 10);
    Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
    Console.WriteLine(string.Join(", ", Seq.TakeAllButLast().Select(x => x.ToString()).ToArray()));
}

或者作为一个通用的解决方案,丢弃最后n个项目(使用评论中建议的队列):

public static IEnumerable SkipLastN(this IEnumerable source, int n) {
    var  it = source.GetEnumerator();
    bool hasRemainingItems = false;
    var  cache = new Queue(n + 1);
    do {
        if (hasRemainingItems = it.MoveNext()) {
            cache.Enqueue(it.Current);
            if (cache.Count > n)
                yield return cache.Dequeue();
        }
    } while (hasRemainingItems);
}
static void Main(string[] args) {
    var Seq = Enumerable.Range(1, 4);
    Console.WriteLine(string.Join(", ", Seq.Select(x => x.ToString()).ToArray()));
    Console.WriteLine(string.Join(", ", Seq.SkipLastN(3).Select(x => x.ToString()).ToArray()));
}

0
0 Comments

Enumerable.SkipLast(IEnumerable, Int32) 方法是在.NET Standard 2.1中添加的,正好可以满足您的需要。

IEnumerable sequence = GetSequenceFromExpensiveSource();
var allExceptLast = sequence.SkipLast(1);

来源自https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.skiplast

返回一个新的可枚举集合,该集合包含源集合中省略了最后count个元素后的元素。

0