2016-06-15 32 views
1

考慮以下幾點:OrderBy ThenBy - 獲取剩餘(相等)物品的最簡單方法?

new[] { 
    new { A = 3, B = 3 }, 
    new { A = 2, B = 2 }, 
    new { A = 2, B = 2 }, 
    new { A = 1, B = 1 } 
} 
.OrderBy(x => x.A) 
.ThenBy(x => x.B) 
.ToList(); 

List將包含以下數據,按以下順序:

[{A = 1,B = 1},{A = 2,B = 2},{A = 2,B = 2},{A = 3,B = 3}]

如何識別這些物品12相等?當所有OrderBy/ThenBy語句已執行並且仍有相同的項目(無法排序)時,我希望'我的代碼到throw

,想象中的項目是非常複雜的(有很多的屬性),並且有一百萬OrderBy/ThenBy報表,以及大量的數據。我寧願避免數據的另一次迭代。

+2

也許在不同的地方打電話? –

+0

對不起,我已經在我的問題中澄清了這一點:我正在尋找一些與LINQ一起玩的東西,即不需要再次迭代數據。 – Simeon

回答

3

你可以這樣做之前你排序。識別重複的最簡單方法是使用GroupBy

由於您使用的匿名類型,你可以通過自己的項目組:

var data = 
    new[] { 
     new { A = 3, B = 3 }, 
     new { A = 2, B = 2 }, 
     new { A = 2, B = 2 }, 
     new { A = 1, B = 1 } 
    }; 

var groups = data.GroupBy(x => x); // works since we are using anonymous types that use value equality 

if(groups.Any(g => g.Count() > 1) 
{ 
    // throw exception 
} 

var result = groups.Select(g=>g.Key) 
        .OrderBy(x => x.A) 
        .ThenBy(x => x.B) 
        .ToList(); 

如果您使用的不是現實中的匿名類型則只是要用來定義屬性組「平等」。

您還可以檢查連續重複的「內聯」使用擴展方法:

public static IEnumerable<T> ThrowIfConsecutiveItemsAreEqual<T>(this IEnumerable<T> source) 
{ 
    bool isFirst = true; 
    T prev = default(T); 
    foreach(var item in source) 
    { 
     if(!isFirst && item.Equals(prev)) 
      throw new Exception(); // TODO: use a better exception type and message 

     yield return item; 

     isFirst = false; 
     prev = item; 
    } 
} 

調用擴展方法ToList之前避免多個枚舉:

var query = 
    new[] { 
    new { A = 3, B = 3 }, 
    new { A = 2, B = 2 }, 
    new { A = 2, B = 2 }, 
    new { A = 1, B = 1 } 
} 
.OrderBy(x => x.A) 
.ThenBy(x => x.B) 
.ThrowIfConsecutiveItemsAreEqual() 
.ToList(); 
+0

這增加了程序O(n)...我正在尋找更好的方法,像'ThenWithTheRest(...)',但沒有一個愚蠢的名字。 – Simeon

+0

@Simeon沒有'OrderBy'的重載,如果找到重複則拋出。如果你想要做某件事的話,它會命令你必須自己推出它。 –

+0

@Simeon我想了一下,想出了一個可能的解決方案。查看我的更新。 –

0

爲了找到以這種方式複製您只需要在排序後查看之前的項目:

static IEnumerable<C> Deduplicate(this IEnumerable<C> items) { 
C last = null; 
foreach (var item in items) { 
    if (last != null && last.A == item.A && last.B == item.B) { 
    //duplicate, handle as you like 
    } 

    last = item; 
    yield return item; 
} 

將這種邏輯分解有多種方式,但這是基本思想。我發現編寫一個幫助器迭代器很有用,它可以爲我返回相同的序列,但每個項目都有前一個項目。使用該幫助程序,您不必再編寫自定義迭代器。

相關問題