【问题标题】:How does this "Sort((x, y) => x.CompareTo(y))" work? [duplicate]这个“排序((x,y)=> x.CompareTo(y))”是如何工作的? [复制]
【发布时间】:2023-03-25 20:43:01
【问题描述】:
Please look at this block of code:
        List<int> list = new List<int>();
        list.Add(1);
        list.Add(6);
        list.Add(2);
        list.Add(3);
        list.Add(8);
        list.Sort((x, y) => x.CompareTo(y));
        int[] arr = list.ToArray();
        foreach (var i in arr)
        {
            Console.WriteLine(i);
        }

我知道在执行时,上面的代码会按升序打印列表。如果我在“x.CompareTo(y)”中切换 x 和 y 的位置,那么列表将按降序排序。我知道 CompareTo() 的作用,但是在这里它如何与 x 和 y 一起决定排序顺序? x 和 y 在这里代表什么?

【问题讨论】:

  • (x, y) =&gt; x.CompareTo(y) 被称为比较器函数。当List.Sort() 方法实现的排序算法需要比较列表中的两个值以确定它们的相对顺序时,它会委托给这个比较器函数以确定它们应该如何重新排序。
  • xy 是传递给 lambda 表达式 x.CompareTo(y) 的参数。见重复。您应该将此 URL 加入书签:docs.microsoft.com/en-us/dotnet/csharp。确保您首先在此处查找您可能对语言语法有任何新问题。

标签: c#


【解决方案1】:

Sort方法签名是public void Sort(Comparison&lt;T&gt; comparison),如果你看到Comparison的声明是public delegate int Comparison&lt;in T&gt;(T x, T y)

只需查看 Comparison 的 cmets。

//
// Summary:
//     Represents the method that compares two objects of the same type.
//
// Parameters:
//   x:
//     The first object to compare.
//
//   y:
//     The second object to compare.
//
// Type parameters:
//   T:
//     The type of the objects to compare.
//
// Returns:
//     A signed integer that indicates the relative values of x and y, as shown in the
//     following table.
//     Value – Meaning
//     Less than 0 –x is less than y.
//     0 –x equals y.
//     Greater than 0 –x is greater than y. 

所以它对顺序中的所有元素进行比较,如果你交换 x 和 y,那么它会做相反的事情。

【讨论】:

    【解决方案2】:

    简单来说,(x, y) =&gt; x.CompareTo(y) 就像一个方法的单行版本 - 它有各种名称,通常是“lambda”或“delegate”。您可以将其视为一种尽可能精简的方法。这是完整的方法,我将在稍后讨论剥离它:

    int MyComparer(int x, int y){
      return x.CompareTo(y);
    }
    

    列表将执行排序,并在每次要选择它正在考虑的两个整数中的哪一个大于另一个时调用此方法。它如何进行排序无关紧要,可能是快速排序,但最终它通常会想知道 x 是否大于、等于或小于 y

    你可以采用我在那里写的那个方法,然后用它调用 sort:

    yourList.Sort(MyComparer)
    

    因此,c# 有这样一个概念,即能够以与传递可变数据相同的方式传递方法。通常,当你传递一个方法时,你会说“当你需要知道你想知道的东西时,你应该调用一些逻辑”——就像自定义排序算法一样,你可以通过改变传入的逻辑来改变

    在剥离 MyComparer 时,嗯.. 我们知道这个列表充满了整数,所以我们知道 x 和 y 是整数,所以我们可以把“int”扔掉。我们也可以去掉方法名,因为它只有一行,我们可以去掉大括号。 return 关键字也是不必要的,因为根据定义,单行必须评估为可返回的东西,并且它应该被隐式返回。 => 将参数与正文逻辑分开

    (method,parameters) => logic_that_produces_a_value(
    

    这样冗长的方法可以归结为

    (x,y) => x.CompareTo(y)
    

    x,y 是列表包含的任何类型,结果值为 -1、0 或 1,列表将使用该列表来确定 x 和 y 如何关联排序。它们可以被称为任何东西;就像你声明一个方法 MyMethod(int left, int right) 并选择调用参数“left”和“right”一样,这里我们做同样的事情,因为这只是声明名称参数 - 你可以轻松编写 (left,right) =&gt; left.CompareTo(right) 并且它可以工作一样的

    您会在 c# 中看到很多,因为 c# 开发人员非常专注于以紧凑的方式表示逻辑。通常,使某些东西变得灵活和强大的最有用的方法是实现一些逻辑,然后让另一个开发人员完成逻辑。微软实现了排序到列表,但他们让我们来决定“哪个更大或更小”,这样我们就可以提供影响排序顺序的逻辑。他们只是要求“任何时候我们想知道两件事是哪一种方式,我们会问你”——这意味着他们不需要 SortAscending 和 SortDescending——我们只是翻转逻辑并声明 10 小于 9 如果我们希望 10 个排在第一位。

    LINQ 严重依赖“为我提供一些逻辑” - 您可能正在列表中查找所有小于 3 的整数:

    myList.Where(item => item < 3)
    

    LINQ 将遍历列表,在此处对每个项目调用您提供的逻辑 (lambda),并仅提供您的 lambda 为 true 的那些。 item 是列表条目之一,在本例中为 int。如果列表包含 Person 对象,item 将是一个 Person。为此,我建议将其称为 pperson 以使其更清楚。当您开始使用更复杂的 lambda 表达式时,这将变得很重要,例如

    string[] wantedNames = new [] { "John", "Luke" };
    people.Where(p => wantedNames.Any(n => p.Name == n));
    

    这会声明您要查找的多个姓名,然后在人员列表中搜索姓名在所需姓名列表中的所有人员。对于每个人 p,LINQ 都会询问“wantedNames,对于这个提供的逻辑,你的任何元素是否返回 true”,然后它循环调用你提供的逻辑的 WantedNames(n,来自 WantedNames 的项目等于人名?)。

    在这里,您使用了两种不同的方法,它们采用 LINQ 重复调用的自定义逻辑 - 哪里是采用委托的方法,Any 也是; Any 对名称列表进行操作,Where 对人员列表进行操作,因此使用变量名称保持清楚哪个是 Person p 哪个是名称字符串 n 比使用 a 和 b 之类的平淡名称要好。

    更深入地了解您的 Sort 方法,请参阅文档:

    查看 List.Sort(Comparer) 了解更多信息 https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort?view=net-5.0#System_Collections_Generic_List_1_Sort_System_Comparison__0__

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多