C#の:SkipLast実装
-
13-09-2019 - |
質問
私は私のシーケンスのすべてが、最後の項目を与える方法を必要としていました。これは私の現在の実装である。
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 には、行う必要のMaxBy
とMinBy
方法と私の方法のようなものを持っています同じが、最大または最小のものを除いてすべてのアイテムを返す。
解決
これは、トリッキーです:あなたは、次のいずれかを取得しようとするまで、あなたは最後の要素を持っていることを伝えることはできません。それはなんとかですが、あなたは永久に「の背後にある一つの要素」であることを気にしない場合に限ります。それはあなたの現在の実装では、基本的に何をするかだ、と私はおそらく若干異なるそれを書くと思いますが、それは、大丈夫に見えます。
別のアプローチは、あなたが最初の反復にあった場合を除き、常に以前に返された値が得られ、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(true)
の条件
他のヒント
あなたの実装では、私には完全に正常に見える - それはおそらく、私はそれを行うだろう方法です。
。私はあなたの状況に関連して提案するかもしれない唯一の簡素化は、の他の方法でラウンドの(すなわち、昇順ではなく降順)リストを注文することです。これはあなたのコードでは適切ではないかもしれないが、それはあなたが簡単に最新のものを除くすべての項目を取るためにcollection.Skip(1)
を使用することができるようになります。
、その後、あなたの現在の実装では全く問題ありません。
は、.NET 3.5を使用している場合、私はあなたが使うことができると思います:
public static IEnumerable<T> SkipLast<T>(this IEnumerable<T> source)
{
return source.TakeWhile((item, index) => index < source.Count() - 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);
}
}
(旧答えは廃棄;このコードはテストされ、機能してきた)それは
印刷します
最初
二
FIRST
SECOND
3番目の
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);
}
}