根据条件旋转列表<t>

时间:2017-02-21 17:29:54

标签: c# linq

说我有List<Point> { {5,2}, {7,2}, {3,9} }

我希望我的输出始终以具有最小X值的点开始

类似于:

var output = input.Rotate((x, y) => x.X < y.X));
output = `List<Point> { {3,9}, {5,2}, {7,2} }`

手动不难:

  1. 查找符合条件的对象的索引
  2. 创建新列表
  3. 将索引之间的所有内容添加到该列表
  4. 添加从0到索引1
  5. 的所有内容

    我只是想知道是否有LINQ方式这样做?

2 个答案:

答案 0 :(得分:2)

首先找到最小X值:

var minX = input.Min(p => p.X);

接下来得到X是最小值的第一个出现位置:

var index = input.FindIndex(p => p.X == minX);

现在通过将原件分成两部分来创建一个新列表:

var newInput = input.Skip(index).Concat(input.Take(index));

答案 1 :(得分:1)

您无法一步完成,您需要至少两次遍历数组。但你可以这样做(有点hacky)方法:

var range = Enumerable.Range(0, list.Count);
var index = range.Aggregate((p,c) => list[p].X> list[c].X? c : p);  
var rotated = range.Select(i => list[(i + index) % list.Count]).ToList();

这里是example(使用Tuple而不是Point,但它的原理是相同的)

第一步是找到数组中最低值的index。第二步,他们从该索引开始构建你的新数组并循环。

如果你想将它封装在扩展方法中,你可以这样做:

public static IEnumerable<T> Rotate<T>(this List<T> list, Func<T,T, bool> comparer)
{
    var range = Enumerable.Range(0, list.Count);
    var index = range.Aggregate((p,c) => predicate(list[p],list[c]) ? p : c);       
    return range.Select(i => list[(i + index) % list.Count]);
}

您可以这样称呼:

var output = input.Rotate((x, y) => x.X < y.X));

您传入的函数如果评估为true,则会选择x而不是y