2

シーケンスの最後の項目を除くすべてを取得する方法が必要でした。これは私の現在の実装です:

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
    {
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if(iterator.MoveNext())
                while(true)
                {
                    var current = iterator.Current;
                    if(!iterator.MoveNext())
                        yield break;
                    yield return current;
                }
        }
    }

私が必要としているのは、最後のアイテムを除くすべてのアイテムで何かをすることです。私の場合、さまざまなプロパティを持つ一連のオブジェクトがあります。次に、日付順に注文します。次に、最新のアイテム(注文後の最後のアイテム)を除くすべてのアイテムを調整する必要があります。

実は、私はまだこれらの列挙子などにあまり興味がなく、実際にここに質問する人は誰もいません:pこれが良い実装であるかどうか、またはどこかで小さなまたは大きな失敗をしたかどうかです。または、おそらくこれが問題を引き受けるのが奇妙なものである場合などです。

もっと一般的な実装はメソッドだったと思いAllExceptMaxByます。それがそういうものだからです。MoreLinqにはandメソッドがあり、私のメソッドは同じことをする必要がありますが、最大または最小のものを除くすべてのアイテムを返しますMaxByMinBy

4

6 に答える 6

12

「最後の要素」はマルコフの停止点ではないため、これは注意が必要です。次の要素を取得しようとするまで、最後の要素に到達したとは言えません。それは可能ですが、永続的に「1 つの要素が遅れている」ことを気にしない場合に限ります。それは基本的にあなたの現在の実装が行っていることであり、問​​題ないように見えますが、おそらく少し違った書き方をするでしょう.

別のアプローチはforeach、最初の反復でない限り、常に以前に返された値を生成するを使用することです。

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    T previous = default(T);
    bool first = true;
    foreach (T element in source)
    {
        if (!first)
        {
            yield return previous;
        }
        previous = element;
        first = false;
    }
}

コードに近い別のオプション:

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    using (IEnumerator<T> iterator = source.GetEnumerator())
    {
        if(!iterator.MoveNext())
        {
            yield break;
        }
        T previous = iterator.Current;
        while (iterator.MoveNext())
        {
            yield return previous;
            previous = iterator.Current;
        }
    }
}

これにより、(シーケンスが空の場合に早期終了を行うことにより)深くネストすることが回避され、代わりに「本当の」while条件が使用されます。while(true)

于 2009-06-09T09:43:00.687 に答える
2

.NET 3.5 を使用している場合は、次を使用できると思います。

public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
  return source.TakeWhile((item, index) => index < source.Count() - 1))
}
于 2009-06-09T09:48:30.927 に答える
1

あなたの実装は私には完全に問題ないように見えます-それはおそらく私が行う方法です。

あなたの状況に関連して私が提案する唯一の単純化は、リストを逆に並べることです(つまり、降順ではなく昇順)。これはあなたのコードには適していないかもしれませんが、collection.Skip(1)最新のものを除くすべての項目を単純に使用することができます。

投稿に示していない理由でこれが不可能な場合、現在の実装はまったく問題ありません。

于 2009-06-09T09:42:08.710 に答える
1
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
    if (!source.Any())
    {
        yield break;
    }
    Queue<T> items = new Queue<T>();
    items.Enqueue(source.First());
    foreach(T item in source.Skip(1))
    {
        yield return items.Dequeue();
        items.Enqueue(item);
    }
}
于 2009-06-09T17:30:25.420 に答える
0

(古い回答は破棄されました。このコードはテスト済みで動作します。)
first
second
FIRST
SECOND
THIRDを出力します


public static class ExtNum{
  public static IEnumerable skipLast(this IEnumerable source){
    if ( ! source.Any())
      yield break;
    for (int i = 0 ; i <=source.Count()-2 ; i++ )
      yield return source.ElementAt(i);
    yield break;
  }
}
class Program
{
  static void Main( string[] args )
  {
    Queue qq = new Queue();
    qq.Enqueue("first");qq.Enqueue("second");qq.Enqueue("third");
    List lq = new List();
    lq.Add("FIRST"); lq.Add("SECOND"); lq.Add("THIRD"); lq.Add("FOURTH");
    foreach(string s1 in qq.skipLast())
      Console.WriteLine(s1);
    foreach ( string s2 in lq.skipLast())
      Console.WriteLine(s2);
  }
}
于 2009-06-09T19:23:40.770 に答える
0

すべての回答を組み合わせて、次を使用し<LangVersion>latest<LangVersion>ます。

.NETフィドル

public static class EnumerableExtensions
{
    // Source is T[]

    public static IEnumerable<T> SkipLast<T>(this T[] source, int count) =>
        source.TakeWhile((item, index) => index < source.Length - count);

    public static IEnumerable<T> SkipLast<T>(this T[] source) => source.SkipLast(1);

    // Source is ICollection<T>

    public static IEnumerable<T> SkipLast<T>(this ICollection<T> source, int count) =>
        source.TakeWhile((item, index) => index < source.Count - count);

    public static IEnumerable<T> SkipLast<T>(this ICollection<T> source) => source.SkipLast(1);


    // Source is unknown or IEnumerable<T>

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source, int count)
    {
        switch (source)
        {
            case T[] array:
                return SkipLast(array, count);
            case ICollection<T> collection:
                return SkipLast(collection, count);
            default:
                return skipLast();
        }

        IEnumerable<T> skipLast()
        {
            using IEnumerator<T> iterator = source.GetEnumerator();
            if (!iterator.MoveNext())
                yield break;
            Queue<T> items = new Queue<T>(count);
            items.Enqueue(iterator.Current);
            for (int i = 1; i < count && iterator.MoveNext(); i++)
                items.Enqueue(iterator.Current);
            while (iterator.MoveNext())
            {
                yield return items.Dequeue();
                items.Enqueue(iterator.Current);
            }
        }
    }

    public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
    {
        switch (source)
        {
            case T[] array:
                return SkipLast(array);
            case ICollection<T> collection:
                return SkipLast(collection);
            default:
                return skipLast();
        }

        IEnumerable<T> skipLast()
        {
            using IEnumerator<T> iterator = source.GetEnumerator();
            if (!iterator.MoveNext())
                yield break;
            T previous = iterator.Current;
            while (iterator.MoveNext())
            {
                yield return previous;
                previous = iterator.Current;
            }
        }
    }    
}
于 2022-01-11T21:47:15.783 に答える