2016-12-15 66 views
2

我正在尋找一種方法來實現基於DateTime值確保訂單的集合。我最初的想法是使用SortedSet<T1>使用自定義IComparer<T1>這樣的:基於DateTime的已訂購集合

internal class DateTimeComparer : IComparer<MyType> { 
    public int Compare(MyType x, MyType y) { 
     return x.DateTimeProp.CompareTo(y.DateTimeProp); 
    } 
} 

var sortedSet = new SortedSet<MyType>(new DateTimeComparer()); 

但是作爲設定似乎覆蓋/替換其中有確切的時間戳的所有項目,這並不工作。爲了驗證這個假設,我創建了兩個集合,一個是簡單列表,它在填充後使用DateTime屬性進行排序,另一個是基於SortedSet<T1>的另一個屬性 - >基於該集合的列表中有幾個條目丟失,那些具有完全相同的時間戳的那些。

還有什麼其他的選擇來實現這樣一個集合?

+1

任何你不想把所有東西都添加到列表中然後對其進行排序的原因? –

+0

你嘗試過'SortedList'嗎? (請注意,排序列表比正常列表慢,因爲每次訪問具有索引的項目時,它都執行二進制搜索,而列表將直接爲您提供該索引內的項目) –

+0

一個集合只能包含特定值一次。使用'DateTimeComparer'時,如果兩個值具有相同的時間戳,則認爲它們是相同的,因此即使在考慮其他屬性時值不同,您也只能爲特定時間戳存儲單個值。 –

回答

1

維護項目排序集合的有效方法是使用二叉搜索樹。您當然可以構建自己的二叉搜索樹,但SortedSet<T>類是使用紅黑二叉搜索樹實現的,因此重用該類正是您正在嘗試執行的操作似乎更智能。

SortedSet<T>中物品的排序通過調用IComparer<T>.Compare方法比較物品對來控制。如果此方法返回0,則兩個項目被視爲相等,並且只有其中一個項目將存儲在該集合中。在DateTimeComparer的情況下,您會遇到這樣的問題,只有一個具有指定DateTimePropMyType實例可以存儲在該集合中。

要解決此問題,必須確保使用DateTimeComparer.Compare方法進行比較時,不同的MyType實例永遠不會相等。您可以通過修改代碼來實現這一目標:

class DateTimeComparer : IComparer<MyType> { 

    readonly ObjectIDGenerator idGenerator = new ObjectIDGenerator(); 

    public int Compare(MyType x, MyType y) { 
     if (x.DateTimeProp != y.DateTimeProp) 
      return x.DateTimeProp.CompareTo(y.DateTimeProp); 
     bool firstTime; 
     var xId = idGenerator.GetId(x, out firstTime); 
     var yId = idGenerator.GetId(y, out firstTime); 
     return xId.CompareTo(yId); 
    } 
} 

如果兩個實例有DateTimeProp那麼他們應該根據這些訂購不同的值。這是由最初的if聲明處理的。

如果這兩個值具有相同的DateTimeProp值,則需要根據其他一些條件對其進行排序。您可以使用MyType的其他屬性,但可能會出現這些屬性相同的情況,除非xy引用相同的實例(例如ReferenceEquals(x, y)爲true),否則該方法從不返回0是很重要的。

要處理這個問題,您可以使用ObjectIDGenerator,它將爲不同的實例分配唯一的64位ID值。這些可以進行比較以提供訂購。

請注意,具有相同DateTimeProp值的項目排序將是隨機的但一致。要控制這種排序,您可以使用MyType的其他屬性,但最終,如果兩個不同實例的所有屬性都相同,則必須使用生成的ID來提供排序。

+0

當兩個時間戳相等時,我通過簡單地返回'大於'(1)來解決這個問題。 – artganify