订购列表但仍能访问索引和字段

时间:2012-09-21 20:04:42

标签: c# .net

我正在尝试按特定字段对对象列表进行分组。

稍后,我需要按如下方式使用此列表:

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,因此不能使用for循环,因为ienumerables不适用于列表索引。

有没有办法在foreach循环中实现此功能(不引用索引)?如果没有,是否有其他方式来订购我的列表,不需要将其设置为不可数?

3 个答案:

答案 0 :(得分:3)

四个选项:

  • 使用OrderBy然后ToList获取排序列表。然后你可以使用你现有的代码,虽然我建议在1开始循环而不是从0开始并在第一次迭代中立即断开。
  • 使用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
        }
    }
    

    请注意,遗憾的是,这会对输入进行两次排序。没有内置的避免方法(不调用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

  • 就地排序列表(如果这不会弄乱任何其他内容)

答案 1 :(得分:0)

您可以在循环之前定义myitem previous(其中myitem在列表中的类型相同),然后在每个列表的末尾,将previous设置为当前项目。如果您这样做,请务必检查previous是否为null,因为它第一次没有值。

答案 2 :(得分:0)

这只是Skeet的一个选项的重复。给他支票。

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; } 
}