2

オブジェクトのリストを特定のフィールドでグループ化しようとしています。

後で、このリストを次のように使用する必要があります。

for(i=0; i< list.Count; i++)
{
   if(i == 0)
    continue;

   if (list[i].property != list[i-1].property)
   dosomething;
}

for ループを実行する必要があるので、「このアイテムの直前のアイテムのプロパティが異なっていたら...

リストを並べ替えようとすると問題が発生します。list.GroupBy を実行すると、リスト アイテムのメンバーにアクセスできません。list.OrderBy を実行する場合、それを ienumerable に設定する必要があるため、ienumerables はリスト インデックスでは機能しないため、for ループを使用できません。

この機能を foreach ループで (インデックスを参照せずに) 実装する方法はありますか? そうでない場合、列挙可能に設定する必要のないリストを注文する別の方法はありますか?

4

3 に答える 3

3

4 つのオプション:

  • 並べ替えられたリストを取得するにはOrderBy、次に使用します。ToListその後、既存のコードを使用できますが、ループを 0 から開始して最初の繰り返しですぐに中断するのではなく、1 から開始することをお勧めします。
  • 使用OrderByしてからZip

    var ordered = input.OrderBy(...);
    var zipped = ordered.Zip(ordered.Skip(1),
                             (Previous, Current) => new { Previous, Current });
    
    foreach (var pair in zipped)
    {
        if (pair.Previous.Property == pair.Current.Property)
        {
            ... Whatever you want to do
        }
    }
    

    残念ながら、これにより入力が2回ソートされることに注意してください。それを回避する組み込みの方法はありません(呼び出しToListなどなしで)。確かに、「自己圧縮」拡張メソッドを作成するのはそれほど難しくありません。

  • OrderBy「以前のプロパティ」を使用して保持します。

    var ordered = input.OrderBy(...);
    // This is like using foreach, but with a simple way to get the
    // first item
    using (var iterator = ordered.GetEnumerator())
    {
        if (!iterator.MoveNext())
        {
            return; // Or whatever. No items!
        }
        var previousProperty = iterator.Current.Property;
        while (iterator.MoveNext())
        {
            var currentProperty = iterator.Current.Property;
            if (previousProperty == currentProperty)
            {
                ... Whatever you want to do
            }
            previousProperty = currentProperty;
        }
    }
    
  • を使用してリストをその場でソートします(それが他に何も台無しにならない場合)List<T>.Sort

于 2012-09-21T20:08:34.010 に答える
0

これは、Skeet のオプションの 1 つの繰り返しにすぎません。彼に小切手を渡してください。

ForEach はインデックスを必要としません。ForEach を使用してリストから項目を削除できません。

class Program
{
    static void Main(string[] args)
    {
        List<SortMe> SortMes = new List<SortMe>();

        SortMes.Add(new SortMe("aaa"));
        SortMes.Add(new SortMe("bbb"));
        SortMes.Add(new SortMe("ccc"));
        SortMes.Add(new SortMe("aaa"));
        SortMes.Add(new SortMe("bbb"));
        SortMes.Add(new SortMe("ccc"));
        SortMes.Add(new SortMe("ccc"));
        SortMes.Add(new SortMe("bbb"));
        SortMes.Add(new SortMe("aaa"));
        SortMes.Add(new SortMe("ccc"));
        SortMes.Add(new SortMe("bbb"));
        SortMes.Add(new SortMe("aaa"));

        SortMe SortMeLast = null;

        foreach (SortMe SortMeCurrent in SortMes.OrderBy(x => x.Name))
        {
            Console.WriteLine("   Current     " + SortMeCurrent.Name);
            if (SortMeLast != null)
            {
                if (SortMeCurrent.Name != SortMeLast.Name)
                {
                    // do something
                    Console.WriteLine("Do Something");
                }
            }
            SortMeLast = SortMeCurrent;
        }
        Console.ReadLine();
    }
}
public class SortMe
{
    public string Name { get; set; }
    public SortMe(string name) { Name = name; } 
}
于 2012-09-21T20:49:46.410 に答える
0

myitem previousループの直前 (はリスト内の同じタイプ)を定義し、myitem各リストの最後でprevious現在のアイテムに設定できます。これを行う場合previous、最初は値がないため、必ず null を確認してください。

于 2012-09-21T20:08:38.593 に答える