使用LINQ在列表的开始和结束之间交替

本文关键字:结束 之间 开始 LINQ 列表 使用 | 更新日期: 2023-09-27 17:54:11

假设我有一个列表{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
}

因此,像上面一样排序它们之后,我需要得到交替的元素,所以理想情况下,我想要一个可以应用于此的答案。

使用LINQ在列表的开始和结束之间交替

这是您想要的顺序:

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

这应该能奏效:

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

排序遵循一个模式,这取决于项目,您的排序逻辑存在于匹配第一个和最后一个,匹配第二个和最后一个等等。=> 1, n, 2, n-1,…所以基本上你需要循环list =>

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

对于一组任何项目(不仅仅是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>或其他。

另一个选择是不使用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)你不改变原始数组
2)不创建数据副本在内存中(对于大数组可能是有害的)

你只是以某种特定的方式滚动你已有的数据