C# 基于多个条件的排序列表

C# 基于多个条件的排序列表,c#,list,C#,List,我有一个整数列表,如下所示: A -> 10 10 1 1 1 B -> 10 9 9 7 6 ... lists.OrderByDescending(a => a.Where(b => b == 10).Count()). ThenByDescending(a => a.Where(b => b == 9).Count()). 我想根据他们有多少个10进行分类,然后根据有多少个9、8、7等等,直到1为止 所以在上面的例子中,A应该比B好,因为即使它的总

我有一个整数列表,如下所示:

A -> 10 10 1 1 1
B -> 10  9 9 7 6
...
lists.OrderByDescending(a => a.Where(b => b == 10).Count()).
ThenByDescending(a => a.Where(b => b == 9).Count()).
我想根据他们有多少个10进行分类,然后根据有多少个9、8、7等等,直到1为止

所以在上面的例子中,A应该比B好,因为即使它的总分更少,它也有两个10秒,而不是只有一个

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

我发展出这样的东西:

A -> 10 10 1 1 1
B -> 10  9 9 7 6
...
lists.OrderByDescending(a => a.Where(b => b == 10).Count()).
ThenByDescending(a => a.Where(b => b == 9).Count()).
等等,但这不是一般的


我希望问题是清楚的。。。多谢各位

这将比较列表并返回常规比较结果-根据一个值是大于、等于还是小于另一个值返回-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;
    }

这将比较列表并返回常规比较结果-根据一个值是否大于、等于或小于另一个值返回-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;
    }

您可以创建按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]
这很简单,但不是很有效。如果您需要更好的性能,那么考虑创建自定义比较器。下面是comparer示例,它使用压缩有序序列检查序列中的所有项目是否相同,或者获取第一个不同的项目:

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);
    }
}
它的工作原理非常简单。考虑两个列表:

[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());

结果是一样的。

您可以创建一个查询,其中订单以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]
这很简单,但不是很有效。如果您需要更好的性能,那么考虑创建自定义比较器。下面是comparer示例,它使用压缩有序序列检查序列中的所有项目是否相同,或者获取第一个不同的项目:

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);
    }
}
它的工作原理非常简单。考虑两个列表:

[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());
结果是一样的。

下面的比较器

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);
    }
}
不需要对每个列表进行十次迭代来计算单个元素。

下面的比较器

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


没有对每个列表进行十次迭代,而是对单个元素进行计数。

您尝试过什么吗?请给我们看看你的代码。我更新了我的问题,但代码在这个阶段是非常原始和不完整的。。。没有主意!你试过什么吗?请给我们看看你的代码。我更新了我的问题,但代码在这个阶段是非常原始和不完整的。。。没有主意!只有在列表列表中,我需要根据问题中解释的条件对其进行排序!您想检查一个列表是否比另一个列表大,对吗?但请稍等,我可以将其转换为列表排序。列表列表中只有一个列表,我需要根据问题中解释的条件对其进行排序!您想检查一个列表是否比另一个列表大,对吗?但请稍等,我可以将其转换为列表排序我不知道我可以连接此linq表达式。。。这是一个来自Sergey answer的单一查询,
Enumerable.Range(1,9).Aggregate(lists.OrderByDescending(l=>l.Count(x=>x==10)),(agg,v=>agg.ThenByDescending(a=>a.Count(x=>x==10-v))
@SergeyBerezovskiy这是一个很好的答案,我甚至不知道Zip方法的存在。非常感谢@亚历山德罗不要害怕
foreach
循环。它们非常容易理解,并且通常比适当的linq查询更可读。我不知道我可以连接这个linq表达式。。。这是一个来自Sergey answer的单一查询,
Enumerable.Range(1,9).Aggregate(lists.OrderByDescending(l=>l.Count(x=>x==10)),(agg,v=>agg.ThenByDescending(a=>a.Count(x=>x==10-v))
@SergeyBerezovskiy这是一个很好的答案,我甚至不知道Zip方法的存在。非常感谢@亚历山德罗不要害怕
foreach
循环。它们非常容易理解,并且通常比适当的linq queriesGreat方法更具可读性!为什么要concat int.MinValue?@Alessandro这是一个障碍,以防列表的长度不尽相同-它会使较短的列表排序比较长的列表排序少。如果列表中有其他
int.MinValue
s,它将不起作用,但看起来这不会是一个问题。啊,好的!我的列表总是相同的长度,所以我可以跳过这个检查,对吗?是的,在这种情况下,你可以放弃
Concat
调用。非常感谢,你是我的导师!)伟大的方法!为什么要concat int.MinValue?@Alessandro这是一个障碍,以防列表的长度不尽相同-它会使较短的列表排序比较长的列表排序少。如果列表中有其他
int.MinValue
s,它将不起作用,但看起来这不会是一个问题。啊,好的!我的列表总是相同的长度,所以我可以跳过这个检查,对吗?是的,在这种情况下,你可以放弃
Concat
调用。非常感谢,你是我的导师!)