【问题标题】:Sorting ArrayList with Lambda in Java 8在 Java 8 中使用 Lambda 对 ArrayList 进行排序
【发布时间】:2014-07-05 07:11:57
【问题描述】:

有人可以向我展示一个简单的示例,如何使用新的 lambda 语法在 Java 8 中按字母顺序对 ArrayList 进行排序。

【问题讨论】:

标签: java lambda functional-programming java-8


【解决方案1】:

对于字符串,这会起作用

arrayList.sort((p1, p2) -> p1.compareTo(p2));

【讨论】:

  • 更好:arrayList.sort(String::compareTo)
  • 请注意,.sort(String::compareTo) and .sort(Comparator.naturalOrder()) 都会将 all 大写字母排在任何小写字母之前。通常你想要的是.sort(String::compareToIgnoreCase)
【解决方案2】:

您只是在对Strings 进行排序吗?如果是这样,您不需要 lambda;毫无意义。你只是这样做

import static java.util.Comparator.*;

list.sort(naturalOrder());

...虽然如果您使用 String 字段对对象进行排序,那么它会更有意义:

list.sort(comparing(Foo::getString));

【讨论】:

    【解决方案3】:

    使用list.sort(String::compareToIgnoreCase)

    使用list.sort(String::compareTo)list.sort(Comparator.naturalOrder()) 会给出不正确(即非字母)的结果。它将在 all 小写字母之前对 any 大写字母进行排序,因此数组 ["aAAA","Zzz", "zzz"] 被排序为 ["Zzz", "aAAA", "zzz"]

    【讨论】:

      【解决方案4】:

      假设您有想要按字母顺序排序的名称列表(字符串)。

      List<String> result = names.stream().sorted(
                       Comparator.comparing(n->n.toString())).collect(Collectors.toList());
      

      它工作得很好。

      【讨论】:

      • Comparator 完全不需要。
      【解决方案5】:

      在函数式编程中,您不是使用旧对象来操作它们,而是以这种方式创建新对象:

      list.stream().sorted().map(blah-blah).filter(...)...
      

      【讨论】:

      • 这是不正确的,因为现在流不再包含旧元素,而是映射和过滤的版本。考虑一个你想按人名排序的银行账户:如果你按照你的建议去做,那么你从一个银行账户流开始,到一个人名流结束,而你想以一个又是银行账户流。
      • 一般来说,当你用 FP 风格编写程序时,你不需要迭代保存结果。所以,这一切都是一个列表:list.stream().sorted() 不是对旧列表进行排序,而是创建新列表。
      • 而该列表刚刚变得毫无用处,因为您留下了此人的姓名(在我的示例中),并且您不能再将其(直接)引用回他们的银行帐户.
      • 另外,可能是您的困惑(无可指责)的根源是 OP 请求了一种对列表进行排序的方法,但您只返回一个中间流,您还需要将其存储在某些点,您从答案中省略了。通过尝试实现这一点,您自己也可能会看到问题。
      • @skiwi 不需要指定排序运算符,因为 OP 想要按字典顺序对 Strings 进行排序,这是默认行为。
      【解决方案6】:

      Lambda 不应该是目标。在您的情况下,您可以像在 Java 1.2 中一样对其进行排序:

      Collections.sort(list); // case sensitive
      Collections.sort(list, String.CASE_INSENSITIVE_ORDER); // case insensitive
      

      如果你想用 Java 8 的方式来做:

      list.sort(Comparator.naturalOrder()); // case sensitive
      list.sort(String.CASE_INSENSITIVE_ORDER); // case insensitive
      

      您也可以使用list.sort(null),但我不建议这样做,因为它不是类型安全的。

      【讨论】:

        【解决方案7】:

        一个真正通用的解决方案是引入一些 StreamUtil 之类的

        public class StreamUtil {
        
            private StreamUtil() {
            }       
        
            @SuppressWarnings({ "rawtypes", "unchecked" })
            public static <TYPE> Comparator<TYPE> sort(Function<TYPE, ? extends Comparable> getterFunction, boolean descending) {
                if (descending) {
                    return (o1, o2) -> getterFunction.apply(o2).compareTo(getterFunction.apply(o1));
                }
                return (o1, o2) -> getterFunction.apply(o1).compareTo(getterFunction.apply(o2));
            }
        
        }
        

        调用看起来像

        list.stream().sorted(sort(YourClass::getSortProperty, true));
        

        【讨论】:

          【解决方案8】:

          最简洁:

          Collections.sort(stringList, String::compareToIgnoreCase);
          

          【讨论】:

            【解决方案9】:

            如果您有一个包含自然排序元素的数组(即Stringintdouble);那么可以通过以下方式实现:

            List<String> myList = new ArrayList<>();
            myList.add("A");
            myList.add("D");
            myList.add("C");
            myList.add("B");
            myList.sort(Comparator.comparing(s -> s));
            myList.forEach(System.out::println);
            

            另一方面,如果您有一个对象数组,并且您想根据某种对象字段进行排序,那么您可以使用:

            class User {
                double score;
                // Constructor // Getters // Setters
            }
            
            List<User> users = new ArrayList<>();
            users.add(new User(19d));
            users.add(new User(67d));
            users.add(new User(50d));
            users.add(new User(91d));
            
            List<User> sortedUsers = users
                    .stream()
                    .sorted(Comparator.comparing(User::getScore))
                    .collect(Collectors.toList());
            
            sortedUsers.forEach(System.out::println);
            

            如果排序更复杂,那么您必须编写自己的比较器并将其传入。

            【讨论】:

              【解决方案10】:
               List<Product> list = new ArrayList<>();
                      List<String> list1 = new ArrayList<>();
                      list.add(new Product(1));
                      list.add(new Product(2));
                      list.add(new Product(3));
                      list.add(new Product(10));
               Collections.sort(list, Comparator.comparing((Product p) -> p.id));
                      for (Product p : list) {
                          System.out.println(p.id);
                      }
              
              

              【讨论】:

              • 坚持函数式编程,for (Product p : list) { System.out.println(p.id); } 可以写成 list.stream().forEach(System.out::println);
              【解决方案11】:

              包含自定义比较器的语法非常简单快捷,例如这里被排序的 ArrayList 包含 JSONObjects,我将根据名为“order”的属性对其进行排序:

              arrayList.sort((JSONObject o1, JSONObject o2)->o1.getInt("order")-o2.getInt("order"));
              

              我认为这是一种非常简洁明了的语法,易于阅读并且比非 lambda 语法更简洁。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-08-20
                • 1970-01-01
                • 2016-06-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-07-30
                相关资源
                最近更新 更多