2017-02-21 39 views
-1

說我有一個List<Point> { {5,2}, {7,2}, {3,9} }基於條件旋轉列表<T>

我想我的輸出總是用最小的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

我只是想知道是否有這樣做的LINQ方式這個?

+3

爲什麼不只是'input.OrderBy(p => pX)'? –

+2

請使用循環顯示您的當前代碼,並嘗試使用LINQ方法。 LINQ對你有什麼好處,你在潛在答案中尋找什麼? – CodeCaster

+1

OrderBy不起作用。 OP想要旋轉列表,以便X值最小的點是第一個,但保留列表的順序。 – swatsonpicken

回答

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

只需一步獲取索引會更高效。例如,你可以使用'Aggregate'。 –

+0

@MattBurland不確定它會更有效率,但可能。不過,「Aggregate」會更難以閱讀。 – DavidG

+0

當然,循環兩次而不是三次會更高效(在最糟糕的情況下 - OP的例子恰好就是這樣)。對於一個小列表來說可能並不重要,但它肯定會好很多。 –

1

你不能一步完成,你至少需要兩次迭代陣列。但是,你能做到這一點(有點哈克)做法:

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

你傳遞一個函數,如果它的計算結果爲真,將選擇x而不是y