OrderBy使用LINQ在列表的开头和结尾之间交替

时间:2014-03-27 10:35:57

标签: c# linq

假设我有一个清单{1,3,5,7,9,11}

我想使用像

这样的代码浏览列表
foreach (int myInt in myIntList.OrderBy(...))
{
    /// Do stuff
}

但是这里的顺序是1然后是11然后是3然后是9然后是5然后7.如何按顺序执行此操作?

我的实际情况稍微复杂一点,for循环看起来像这样:

foreach (Tuple<string, int, int, int> im in iconMappings.OrderBy(i => i.Item4).ThenByDescending(i => i.Item3))
{
    // Do stuff
}

所以如上所述对它们进行了排序我需要获得交替元素,所以理想情况下这样可以应用于此。

5 个答案:

答案 0 :(得分:5)

这会给出您想要的订单:

List<int> myIntList = new List<int>(new[] { 1, 3, 5, 7, 9, 11 });

var result = myIntList
    .Select((v, i) => new { Value = v, Index = i })
    .OrderBy(v => Math.Min(v.Index, Math.Abs((myIntList .Count - 1) - v.Index)))
    .Select(v => v.Value);

foreach (var v in result)
{
    Console.WriteLine(v.ToString());
}

给出:

1
11
3
9
5
7

答案 1 :(得分:3)

这应该可以解决问题:

IEnumerable<int> alternatingOrder = intList
    .Select((i, index) => new
    {
        i,
        Margin = index < intList.Count / 2 ? index : intList.Count - ++index
    })
    .OrderBy(x => x.Margin)
    .Select(x => x.i);

答案 2 :(得分:1)

订购遵循一个模式,取决于项目,您的排序逻辑不存在匹配的第一个和最后一个,匹配第二个和前一个之后,依此类推。 =&GT; 1,n,2,n-1,... 所以基本上你必须遍历list =&gt;

var myNewList = new List<...>();
foreach(int i = 0, i < myItems.Count, i++)
{
myNewList.add(myItems.First());
myNewList.add(myItems.Last());
myItems.Remove(myItems.First());
myItems.Remove(myItems.Last();
}

答案 3 :(得分:1)

针对任何项目(不仅仅是int)的可重复使用的tic-tac方法可以是:

class Program
{
    static void Main(string[] args)
    {
        var numbers = new[] {1, 3, 5, 7, 9, 11, 13};

        foreach (var num in numbers.TicTac())
        {
            Console.WriteLine(num);
        }

        Console.Read();
    }
}

static class Extensions
{
    public static IEnumerable<T> TicTac<T>(this IEnumerable<T> source)
    {
        var count = source.Count();

        var leftIterator = source.GetEnumerator();
        var rightIterator = source.Reverse().GetEnumerator();

        int returned = 0;
        bool right = false;

        while (returned < count)
        {
            if (right)
            {
                rightIterator.MoveNext();
                yield return rightIterator.Current;
            }
            else
            {
                leftIterator.MoveNext();
                yield return leftIterator.Current;
            }

            returned++;
            right = !right;
        }
    }
}

在您的情况下,您要么假设数组已经订购,要么在调用之前订购它。

然后,您可以优化它以了解source是什么,例如,如果sourceT[],或IList<T>或其他什么,则提供更好的实施。

答案 4 :(得分:0)

的另一个选项是不使用OrderBy,而是使用自定义枚举器。 (为了举例,我省略了边界检查和其他东西)

public  IEnumerable<int> GetNext(List<int> data) 
{       
      int leftIndex = 0; 
      int rightIndex = data.Count() -1; 
      while(leftIndex < rightIndex) 
      {
         yield return data[leftIndex++];        
         yield return data[rightIndex--];       

      }
}

一样使用它
foreach(var a in GetNext(list)){...}

这样做的好处是

  

1)你不要改变oringinal阵列
  2)您不创建数据副本   在内存中(在大数组的情况下可能有害)

您只需以某种特定方式滚动您已有的数据。