代码之家  ›  专栏  ›  技术社区  ›  Carl Manaster

很好的将空值排序到底部的一般方法,不管怎样?

  •  8
  • Carl Manaster  · 技术社区  · 15 年前

    我正在编写一些定制的比较器,我希望它们将空项推到列表的底部,不管是升序排序还是降序排序。什么样的策略或模式可以达到这个目的?

    随便地:

    • 只需单独写升序和 下行比较器,共享代码 在可能的地方
    • 将空处理委托给另一个 通过抛出一个NPE或 通过明确地调用它
    • 包含升旗并放置 要导航的IT条件逻辑 在山谷周围
    • 将常规比较器包装在 空处理类

    还有其他策略吗?我想听听关于不同方法的任何经验,以及各种策略的任何陷阱。

    5 回复  |  直到 7 年前
        1
  •  5
  •   Jon Skeet    15 年前

    最后一个选择对我很有吸引力。比较器真的很适合连接在一起。尤其是你可能很想写一篇 ReverseComparator 以及A NullWrappingComparator .


    编辑:你不必自己写。如果你看 Ordering 类中 Google Collections Library 你会发现这个和其他各种各样的好东西:)


    编辑:更详细地说明我的意思 反向比较器

    一个警告词-在 反向比较器 ,颠倒参数的顺序,而不是否定结果,否则 Integer.MIN_VALUE 与自身“相反”。

    所以这个实现是错误的(假设 original 比较器是否反转):

    public int compare(T x, T y)
    {
        return -original.compare(x, y);
    }
    

    但这是对的:

    public int compare(T x, T y)
    {
        return original.compare(y, x);
    }
    

    原因是我们总是想逆转比较,但是如果 original.compare(x, y) 收益率 int.MIN_VALUE 那么坏的比较器会 返回 极小值 ,这是不正确的。这是因为有趣的特性 int.MIN_VALUE == -int.MIN_VALUE .

        2
  •  10
  •   dfa    15 年前

    我同意乔恩·斯基特的观点(这很简单)。我试图实现一个非常简单的 decorator :

    class NullComparators {
    
        static <T> Comparator<T> atEnd(final Comparator<T> comparator) {
            return new Comparator<T>() {
    
                public int compare(T o1, T o2) {
                    if (o1 == null && o2 == null) {
                        return 0;
                    }
    
                    if (o1 == null) {
                        return 1;
                    }
    
                    if (o2 == null) {
                        return -1;
                    }
    
                    return comparator.compare(o1, o2);
                }
            };
        }
    
        static <T> Comparator<T> atBeginning(final Comparator<T> comparator) {
            return Collections.reverseOrder(atEnd(comparator));
        }
    }
    

    给定比较器:

    Comparator<String> wrapMe = new Comparator<String>() {
          public int compare(String o1, String o2) {
              return o1.compareTo(o2);
          }
    };
    

    一些测试数据:

    List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);
    

    可以在结尾处使用空值进行排序:

    Collections.sort(strings, NullComparators.atEnd(wrapMe));
    
    [aaa, bbb, ccc, null, null, null]
    

    或在开始时:

    Collections.sort(strings, NullComparators.atBeginning(wrapMe));
    
    [null, null, null, ccc, bbb, aaa]
    
        3
  •  5
  •   Carl Manaster    15 年前

    跟进DFA的答案——我想要的是,nulls在末尾排序,而不影响非nulls的顺序。所以我想要更多的东西:

    public class NullComparatorsTest extends TestCase {
        Comparator<String>  forward = new Comparator<String>() {
                                        public int compare(String a, String b) {
                                            return a.compareTo(b);
                                        }
                                    };
    
        public void testIt() throws Exception {
            List<String> strings = Arrays.asList(null, "aaa", null, "bbb", "ccc", null);
            Collections.sort(strings, NullComparators.atEnd(forward));
            assertEquals("[aaa, bbb, ccc, null, null, null]", strings.toString());
            Collections.sort(strings, NullComparators.atBeginning(forward));
            assertEquals("[null, null, null, aaa, bbb, ccc]", strings.toString());
        }
    }
    
    public class NullComparators {
        public static <T> Comparator<T> atEnd(final Comparator<T> comparator) {
            return new Comparator<T>() {
                public int compare(T a, T b) {
                    if (a == null && b == null)
                        return 0;
                    if (a == null)
                        return 1;
                    if (b == null)
                        return -1;
                    return comparator.compare(a, b);
                }
            };
        }
    
        public static <T> Comparator<T> atBeginning(final Comparator<T> comparator) {
            return new Comparator<T>() {
                public int compare(T a, T b) {
                    if (a == null && b == null)
                        return 0;
                    if (a == null)
                        return -1;
                    if (b == null)
                        return 1;
                    return comparator.compare(a, b);
                }
            };
        }
    }
    

    不过,这完全归功于德国足协——这只是对他的工作的一个小小的修改。

        4
  •  3
  •   Ali Dehghani    8 年前

    在Java 8中,可以使用 Comparator.nullsLast Comparator.nullsFirst 静态方法有更多的空友好比较器。假设你有一个 Fruit 类如下:

    public class Fruit {
        private final String name;
        private final Integer size;
    
        // Constructor and Getters
    }
    

    如果你想把一堆水果按大小分类并放在 null 最后:

    List<Fruit> fruits = asList(null, new Fruit("Orange", 25), new Fruit("Kiwi", 5));
    

    你可以简单地写:

    Collections.sort(fruits, Comparator.nullsLast(Comparator.comparingInt(Fruit::getSize)));
    

    结果是:

    [Fruit{name='Kiwi', size=5}, Fruit{name='Orange', size=25}, null]
    
        5
  •  2
  •   Duncan Jones    10 年前

    你可以一直使用 NullComparator 来自公共集合。它的存在时间比谷歌的收藏要长。