基于另一个对象列表排序

时间:2015-01-05 16:38:51

标签: c# linq sorting

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

我有两个产品清单,我想以与第一个相同的顺序重新排序第二个产品清单。 如何重新排序产品列表,以便结果如下:&#34; BBB&#34;,&#34; HHH&#34;,&#34; ZZZ&#34;?

编辑:将@Chanr提及的代码属性更改为公开

5 个答案:

答案 0 :(得分:3)

您可以使用IndexOf

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

唯一的问题是,如果第二个列表中的某些内容不在第一个列表中,那么这些内容将转到第二个列表的开头。

IndexOf {{1}}上的MSDN帖子可以找到here

答案 1 :(得分:2)

你可以试试这样的事情

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

如果它是相同的Product对象。否则,您可以尝试类似:

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

并编写一个小的GetIndex辅助方法。或者为Index()创建List<>扩展方法,这将产生

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

GetIndex方法相当简单,所以我在这里省略它。

(我没有PC运行代码所以请原谅小错误)

答案 2 :(得分:1)

这是一种有效的方法:

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)运行时间。

答案 3 :(得分:0)

我会实现一个比较函数,它使用哈希表从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

答案 4 :(得分:0)

轻松自如:

IEnumerable<Product> result = 

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

这将提供所需的结果。源列表中没有ProductCodes的对象将放在结果集的开头。对于我想的几百个项目,这将表现得很好。

如果你必须处理成千上万的物品而不是像@ Jon那样的答案可能会表现得更好。在那里,您首先为每个项目创建一种查找值/分数,然后将其用于排序/排序。

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