我在leetcode讨论部分看到了这段代码,但我无法理解它。请在这里帮忙。
HashMap<Character,Integer> map = new HashMap<>();
for(char ch: s.toCharArray()){
map.put(ch,map.getOrDefault(ch,0)+1);
}
List<Character> list = new ArrayList<>(map.keySet());//convert hashmap keys into list
list.sort((x,y) -> map.get(y) - map.get(x));
Run Code Online (Sandbox Code Playgroud)
我无法理解下面一行的含义。
list.sort((x,y) -> map.get(y) - map.get(x));
实际上,这短短一行中发生了数量惊人的事情:list.sort((x,y) -> map.get(y) - map.get(x));。
List.sort( Comparator comparator )该List.sort方法需要一个Comparator对象作为参数。
@FunctionalInterface如果您查看该Comparator界面,您\xe2\x80\x99将看到它被注释为@FunctionalInterface. 引用 Javadoc,\xe2\x80\x9c 从概念上讲,函数式接口只有一个抽象方法。\xe2\x80\x9d。
这段代码:
\n(x,y) -> map.get(y) - map.get(x)\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\xa6 是 lambda 语法,充当该单个抽象方法的实现。
\n该 lambda 是用紧凑的语法编写的。您可能会发现扩展格式很容易解释。
\n( String x , String y ) -> { return map.get( y ) - map.get( x ); }\nRun Code Online (Sandbox Code Playgroud)\n\xe2\x80\xa6 如:
\nlist.sort( ( String x , String y ) -> { return map.get( y ) - map.get( x ); } );\nRun Code Online (Sandbox Code Playgroud)\n编译器知道需要一个Comparator对象作为 的参数List#sort。因此, 编译器可以推断这个 lambda 实现的方法应该是 的compare方法Comparator,这是在 上找到的唯一抽象方法Comparator。
Comparator#compare该Comparator#compare方法返回一个int整数。引用 Javadoc:返回的数字表示 \xe2\x80\x9ca 负整数、零或正整数,因为第一个参数小于、等于或大于第二个参数。\xe2\x80\x9d。
您的键值对的值侧HashMap属于类型Integer类。因此,仅仅Integer从一个值对象中减去另一个值对象是一种看似聪明的方法,可以确定该数字要返回的整数compare。
\xe2\x9a\xa0\xef\xb8\x8f 然而,正如下面评论的,上述方法在数学上是有缺陷的。减法可能会导致整数溢出。
\nInteger.compare最好将比较工作委托给类中的方法Integer:Integer.compare。
( x , y ) -> Integer.compare( x , y ) \nRun Code Online (Sandbox Code Playgroud)\n示例代码:
\n(x,y) -> map.get(y) - map.get(x)\nRun Code Online (Sandbox Code Playgroud)\n运行时:
\n( String x , String y ) -> { return map.get( y ) - map.get( x ); }\nRun Code Online (Sandbox Code Playgroud)\n我们看到我们的列表排序为Bob, Carol, Alice,顺序为 (42, 7, 2)。
如果对该方法的实现感到好奇,请检查OpenJDK 项目上的开源代码代码。摘抄:
\npublic static int compare(int x, int y) {\n return (x < y) ? -1 : ((x == y) ? 0 : 1);\n}\nRun Code Online (Sandbox Code Playgroud)\nComparator.comparingInt另一种方法是使用Comparatorstatic 返回的对象Comparator.comparingInt方法返回的对象。您的 IDE(例如 IntelliJ)甚至可能会建议此代码。
list.sort( Comparator.comparingInt( list :: get ) )\nRun Code Online (Sandbox Code Playgroud)\n对静态方法的调用Comparator.comparingInt返回一个Comparator对象。正是我们需要传递给List#sort方法的内容。
该map :: get部分是方法参考。
例子:
\nlist.sort( ( String x , String y ) -> { return map.get( y ) - map.get( x ); } );\nRun Code Online (Sandbox Code Playgroud)\n您的示例代码实际上按降序而不是升序对数字顺序进行排序。
\n如果您想要这种效果,可以使用类中的另一个方便的方法来实现Comparator:reversed。
使用方法链接来追加.reversed,如下所示:Comparator.comparingInt( map :: get ).reversed()。
( x , y ) -> Integer.compare( x , y ) \nRun Code Online (Sandbox Code Playgroud)\n结果:
\n// Source of data.\nfinal Map < String, Integer > map =\n Map.of(\n "Alice" , 42 ,\n "Bob" , 2 ,\n "Carol" , 7\n );\nSystem.out.println( "map = " + map ); // Be aware that a Map can iterate in any order at any time.\n\n// Unsorted list.\nfinal List < String > list = new ArrayList <>( map.keySet() ); // List may be built from a map in any order, given that a map iterates in no particular order.\nSystem.out.println( "list = " + list );\n\n// Sorted list.\nlist.sort( ( String x , String y ) -> { return Integer.compare( map.get( x ) , map.get( y ) ); } );\nSystem.out.println( "list = " + list );\nRun Code Online (Sandbox Code Playgroud)\n我们看到新的结果Alice, Carol, Bob(42, 7, 2) 与之前的结果相反Bob, Carol, Alice(42, 7, 2) 与之前的(2, 7, 42)
此外,该map.get(y) - map.get(x)部分还会调用自动装箱。
每次get调用都会返回一个类型为 class 的对象Integer。-直接对对象使用减号Integer是没有意义的;物体不能被减去。然而,编译器足够聪明,可以识别Integer对象可以转换为int基元。还有两个int基元可以相减。
顺便说一下,Characterclass 是原始类型的包装类char。自 Java 2 以来,两者都已本质上被破坏,而自 Java 5 以来,两者都已被破坏。作为 16 位值,achar在物理上无法表示大多数字符。
相反,在处理单个字符时,请学习使用代码点整数。Unicode 中定义的 144,697 个字符中的每一个都被永久分配了一个特定的数字。数字范围从零到略多于一百万。
\n您将在、、等codePoint\xe2\x80\xa6类上找到方法。StringCharacterStringBuilder