根据多个条件对列表进行排序

时间:2014-09-15 07:49:39

标签: c# list

我有一个整数列表列表,如:

A -> 10 10 1 1 1
B -> 10  9 9 7 6
...

我想根据他们有多少10个,然后是多少9s,8s,7s等等来对它们进行排序

因此,在上面的示例中,A应该优于B,因为即使总点数较少,它也有两个10而不是一个。

代码应该是通用的,因为我不知道每种情况可以使用多少个数字(有时10个,有时5个,甚至只有3个)。

我开发了类似的东西:

lists.OrderByDescending(a => a.Where(b => b == 10).Count()).
ThenByDescending(a => a.Where(b => b == 9).Count()).

依此类推,但这不是通用的......

我希望问题很清楚......非常感谢你!

3 个答案:

答案 0 :(得分:2)

您可以创建按数量为10的订单列表查询,然后通过为9到1的数字添加其他订单来撰写查询:

var query = lists.OrderByDescending(l => l.Count(x => x == 10));

for (int i = 9; i >= 1; i--)
    query = query.ThenByDescending(l => l.Count(x => x == i));

对于这些样本列表:

var lists = new[] { 
    new[] { 10, 9, 9, 8, 7 }, 
    new[] { 10, 9, 9, 7, 6 },
    new[] { 10, 10, 1, 1, 1 }
};

结果将是:

[10, 10, 1, 1, 1]
[10, 9, 9, 8, 7]
[10, 9, 9, 7, 6]

这很简单,但效率不高。如果您需要更好的性能,请考虑创建自定义比较器。以下是带有比较器的示例,它使用压缩有序序列来检查序列中的所有项目是否相同,或者获取不同的第一项:

public class CustomComparer : Comparer<IList<int>>
{
    public override int Compare(IList<int> x, IList<int> y)
    {            
        var comparisons = x.Zip(y, (a,b) => a.CompareTo(b));

        foreach(var comparison in comparisons)
        {
            if (comparison != 0)
                return comparison;
        }

        return x.Count.CompareTo(y.Count);
    }
}

注意:如果没有订购列表中的项目,那么您应该在压缩之前对它们进行排序:

var comparisons = 
    x.OrderByDescending(i => i)
     .Zip(y.OrderByDescending(i => i), (a,b) => a.CompareTo(b));

它非常简单。考虑两个列表:

[10, 9, 9, 8, 7, 5]
[10, 9, 9, 7, 6]

它将在相应的位置创建成对的项目:

{10,10}, {9,9}, {9,9}, {8,7}, {7,6}

然后逐一比较每对中的项目,直到找到第一个不匹配:

0, 0, 0, 1 (four comparisons only)

这意味着第一个列表比第二个列表多8个。用法:

var query = lists.OrderByDescending(i => i, new CustomComparer());

结果相同。

答案 1 :(得分:1)

比较列表并返回常规比较结果 - 返回1,0或-1,具体取决于一个值是否大于,等于或小于另一个值。

    static int CompareLists(List<int> a, List<int> b)
    {
        var grpA = a.GroupBy(p => p).ToDictionary(k=>k.Key,v=>v.Count());
        var grpB = b.GroupBy(p => p).ToDictionary(k=>k.Key,v=>v.Count());
        for (int i = 10; i >= 0; i--)
        {
            int countA = grpA.ContainsKey(i) ? grpA[i] : 0;
            int countB = grpB.ContainsKey(i) ? grpB[i] : 0;
            int comparison = countA.CompareTo(countB);
            if (comparison != 0)
                return comparison;
        }
        return 0;
    }

首先,我们将列表转换为number->amount of occurences的字典。 然后我们迭代从10到0的数字并比较出现的次数。如果结果为0,那么我们转到另一个数字。

如果您要List<List<int>>进行排序,只需使用list.Sort(CompareLists),如下所示:

        List<int> d = new List<int> { 10, 6, 6 };
        List<int> b = new List<int> { 10, 9, 9 };
        List<int> a = new List<int> { 10, 10, 1, 1, 1 };
        List<int> c = new List<int> { 10, 7, 7 };
        List<int> e = new List<int> { 9, 3, 7 };
        List<int> f = new List<int> { 9, 9, 7 };
        List<List<int>> list = new List<List<int>>() { a, b, c, d, e, f };
        list.Sort(CompareLists);

答案 2 :(得分:1)

以下比较器

public class Comparer : IComparer<IEnumerable<int>>
{
    public int Compare(IEnumerable<int> a, IEnumerable<int> b)
    {
        var aOrdered = a.OrderByDescending(i => i).Concat(new[] { int.MinValue });
        var bOrdered = b.OrderByDescending(i => i).Concat(new[] { int.MinValue });
        return a.Zip(b, (i, j) => i.CompareTo(j)).FirstOrDefault(c => c != 0);
    }
}

允许您订购列表列表

var result = lists.OrderByDescending(i => i, new Comparer());

没有遍历每个列表十次计算单个元素。