簡體   English   中英

基於另一個列表的C#排序列表

[英]C# Sort List Based on Another List

我有一個包含多個List <>的類。 它基本上是一個表,每個列都存儲為List <>。 每個列不包含相同的類型。 每個列表的長度也相同(元素數相同)。

例如:

我有3個List <>對象; 一個列表,兩個列表和三個列表。

//Not syntactically correct
List<DateTime> one = new List...{4/12/2010, 4/9/2006, 4/13/2008};
List<double> two = new List...{24.5, 56.2, 47.4};
List<string> three = new List...{"B", "K", "Z"};

我希望能夠從最舊到最新對列表進行排序:一個= {4/9/2006,4/13/2008,4/12/2010};

為此,我將元素0移到了末尾。

然后,我想以相同的方式對清單2和清單3進行排序。 將第一個移動到最后一個。

因此,當我對一個列表進行排序時,我希望其他列表中相應索引中的數據也根據對一個列表的排序方式進行更改。

我猜想我必須以某種方式使IComparer重載,但是我覺得還有一個我沒有意識到的捷徑。

過去,我通過保留或創建單獨的索引列表來處理此設計。 您首先對索引列表進行排序,然后使用它對其他列表進行排序(或訪問)。 您可以通過為索引列表創建自定義IComparer來實現。 您在IComparer內部所做的是根據鍵列表中的索引進行比較。 換句話說,您正在間接地對索引列表進行排序。 就像是:

// This is the compare function for the separate *index* list.
int Compare (object x, object y)
{
  KeyList[(int) x].CompareTo(KeyList[(int) y])
}

因此,您正在根據鍵列表中的值對索引列表進行排序。 然后,您可以使用該排序的鍵列表對其他列表進行重新排序。 如果不清楚,我將在遇到情況后嘗試添加一個更完整的示例。

我很遺憾地說,但這感覺像是一個不好的設計。 特別是因為List <T>在調用排序操作之一之前不保證元素順序(因此在插入時會遇到問題):

從MSDN

不能保證對列表進行排序。 您必須先對列表進行排序,然后再執行需要對列表進行排序的操作(例如BinarySearch)。

在很多情況下,您不會因此而遇到麻煩,但是您可能並且如果這樣做的話,可能很難找到它。 例如,我認為List <T>的當前框架實現會保持插入順序,直到調用sort為止,但將來可能會改變。

我將認真考慮使用其他數據結構進行重構 如果仍然要基於此數據結構實現排序,則可以創建一個臨時對象(也許使用匿名類型),對其進行排序,然后重新創建列表( 有關此方法的解釋, 請參見此出色的答案 )。

這是使用LINQ和投影來實現的方法。 第一個查詢生成一個數組,其原始索引按datetime值重新排序; 在您的示例中,newOrdering數組將具有以下成員:

{ 4/9/2006, 1 }, { 4/13/2008, 2 }, { 4/12/2010, 0 }

第二組語句通過使用重新排序的索引選擇項目(即按該順序的項目1、2和0)來生成新列表。

var newOrdering = one
    .Select((dateTime, index) => new { dateTime, index })
    .OrderBy(item => item.dateTime)
    .ToArray();

// now, order each list
one = newOrdering.Select(item => one[item.index]).ToList();
two = newOrdering.Select(item => two[item.index]).ToList();
three = newOrdering.Select(item => three[item.index]).ToList();

首先,您應該創建一個Data對象來容納所有內容。

private class Data
{
    public DateTime DateTime { get; set; }
    public int Int32 { get; set; }
    public string String { get; set; }
}

然后,您可以像這樣進行排序。

var l = new List<Data>();
l.Sort(
    (a, b) =>
    {
        var r = a.DateTime.CompareTo(b);
        if (r == 0)
        {
            r = a.Int32.CompareTo(b);
            if (r == 0)
            {
                r = a.String.CompareTo(b);
            }
        }
        return r;
    }
);

使用通用數組,可能會有些麻煩。

一種替代方法是使用Array.Sort()方法,該方法接受鍵數組和值數組進行排序。 它首先將鍵數組按升序排序,並確保將值數組重組以匹配此排序順序。

如果您願意承擔將List<T>轉換為數組(然后返回)的費用,則可以利用此方法。

或者,您可以使用LINQ使用Zip()將來自多個數組的值組合為一個匿名類型,使用鍵字段對匿名類型的列表進行排序,然后將其拆分為單獨的數組。

如果要就地執行此操作,則必須編寫一個自定義比較器並創建一個單獨的索引數組,以維護項目的新順序。

我寫了一種針對Nito.LINQ (尚未發布)執行此操作的排序算法。 它使用思維簡單的QuickSort對列表進行排序,並使任何數量的相關列表保持同步。 源代碼從IList<T>.Sort擴展方法開始。

另外,如果復制數據不是一個大問題,則可以使用Zip運算符(需要.NET 4.0或Rx)將其投影到LINQ查詢中,對其進行排序,然后提取每個結果:

List<DateTime> one = ...;
List<double> two = ...;
List<string> three = ...;
var combined = one.Zip(two, (first, second) => new { first, second })
    .Zip(three, (pair, third) => new { pair.first, pair.second, third });
var ordered = combined.OrderBy(x => x.first);
var orderedOne = ordered.Select(x => x.first);
var orderedTwo = ordered.Select(x => x.second);
var orderedThree = ordered.Select(x => x.third);

自然,最好的解決方案是首先不要分離相關數據。

我希望這可以幫助:

one = one.Sort(delegate(DateTime d1, DateTime d2)
{
    return Convert.ToDateTime(d2).CompareTo(Convert.ToDateTime(d1));
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM