簡體   English   中英

基於另一個對象列表排序

[英]Sorting a list of objects based on another

public class Product
{
    public string Code { get; private set; }

    public Product(string code)
    {
        Code = code;
    }
}

List<Product> sourceProductsOrder = 
              new List<Product>() { new Product("BBB"), new Product("QQQ"), 
                                    new Product("FFF"), new Product("HHH"),
                                    new Product("PPP"), new Product("ZZZ")};

List<Product> products = 
              new List<Product>() { new Product("ZZZ"), new Product("BBB"),
                                    new Product("HHH")};

我有兩個產品清單,我想以與第一個相同的順序重新排序第二個產品清單。 如何重新排序產品列表,以便結果為:“BBB”,“HHH”,“ZZZ”?

編輯: @juharr提到將代碼屬性更改為公共

你會使用IndexOf

var sourceCodes = sourceProductsOrder.Select(s => s.Code).ToList();
products = products.OrderBy(p => sourceCodes.IndexOf(p.Code));

唯一的問題是,如果第二個列表中的某些內容不在第一個列表中,那么它們將轉到第二個列表的開頭。

關於IndexOf MSDN帖子可以在這里找到。

你可以嘗試這樣的事情

products.OrderBy(p => sourceProductsOrder.IndexOf(p))

如果它是相同的Product對象。 否則,您可以嘗試以下方法:

products.OrderBy(p => GetIndex(sourceProductsOrder, p))

並編寫一個小的GetIndex輔助方法。 或者為List<>創建一個Index()擴展方法,它將產生

products.OrderBy(p => sourceProductsOrder.Index(p))

GetIndex方法相當簡單,所以我在這里省略它。

(我沒有PC來運行代碼所以請原諒小錯誤)

這是一種有效的方法:

var lookup = sourceProductsOrder.Select((p, i) => new { p.Code, i })
                                .ToDictionary(x => x.Code, x => x.i);

products = products.OrderBy(p => lookup[p.Code]).ToList();

這應該具有O(N log N)的運行時復雜度,而使用IndexOf()的方法將是O(N 2 )。

這假設如下:

  • sourceProductsOrder中沒有重復的產品代碼
  • sourceProductsOrder包含產品中的所有產品代碼
  • 您使Code字段/屬性非私有

如果需要,您可以使用以下內容替換第一個語句來創建針對第一個項目符號的安全措施:

var lookup = sourceProductsOrder.GroupBy(p => p.Code)
                                .Select((g, i) => new { g.Key, i })
                                .ToDictionary(x => x.Key, x => x.i);

您可以通過將第二個語句替換為以下內容來解釋第二個項目:

products = products.OrderBy(p => 
            lookup.ContainsKey(p.Code) ?  lookup[p.Code] : Int32.MaxValue).ToList();

如果需要,你可以使用兩者。 這些會使算法慢一點,但即使有這些改動,它也應該繼續具有O(N log N)運行時間。

我將實現一個比較函數,它使用哈希表從sourceProductsOrder查找順序。 查找表看起來像

(key) : (value)
"BBB" : 1
"QQQ" : 2
"FFF" : 3
"HHH" : 4
"PPP" : 5
"ZZZ" : 6

然后你的比較可以查找兩個元素的順序並做一個簡單的< (偽代碼):

int compareFunction(Product a, Product b){ 
    return lookupTable[a] < lookupTable[b]
}

構建哈希表將是線性的,並且進行排序通常是nlogn

來得便當去得快:

IEnumerable<Product> result = 

products.OrderBy(p => sourceProductsOrder.IndexOf(sourceProductsOrder.FirstOrDefault(p2 => p2.Code == p.Code)));

這將提供所需的結果。 源列表中沒有ProductCodes的對象將放在結果集的開頭。 對於我想的幾百個項目,這將表現得很好。

如果你必須處理成千上萬的對象而不是像@ Jon那樣的答案可能會表現得更好。 在那里,您首先為每個項目創建一種查找值/分數,然后將其用於排序/排序。

我描述的方法是O(n2)。

暫無
暫無

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

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