【问题标题】:Sorting LinkedHashMap<String, String[]>.entrySet() by the keys, but in the middle of the keys using a regex按键对 LinkedHashMap<String, String[]>.entrySet() 进行排序,但在键的中间使用正则表达式
【发布时间】:2018-01-10 09:23:18
【问题描述】:

我有一个 LinkedHashMap,它将字符串映射到字符串数组。

密钥的格式如下:“xxx (yyy(0.123))

基本上,我希望能够对条目集进行排序,使其按小数部分排序,而不是字符串的开头。到目前为止,我所做的是将条目集转换为 ArrayList,以便我可以尝试对其调用 Arrays.sort,但显然这只会按字符串的开头进行排序。

我目前在想的是,我必须通过这个数组,将对中的每个键转换为一个自定义类,并使用一个比较器来比较我想要的方式(使用正则表达式 .*\((.*)\)\) 到求小数)。但是,这听起来像是一堆不必要的开销,所以我想知道是否有更简单的方法。提前致谢。

【问题讨论】:

    标签: java arrays string sorting dictionary


    【解决方案1】:

    您的解决方案听起来不错。

    如果您遇到性能问题,您可以通过将字符串替换为包含字符串和十进制值的对象来缓冲十进制值。那么在排序过程中就不需要多次重新计算了。

    上述缓冲解决方案需要权衡取舍,而确定哪种技术是最佳的实际上取决于您的整个解决方案。

    【讨论】:

      【解决方案2】:

      您是否有理由需要使用LinkedHashMap? javadoc具体说明

      这个链表定义了迭代顺序,通常是键插入映射的顺序(insertion-order)

      TreeMap 似乎更适合您要实现的目标,这使您可以在施工时提供Comparator。使用 Java 8,这可以通过以下方式实现:

      private static final String DOUBLE_REGEX = "(?<value>\\d+(?:\\.\\d+)?)";
      private static final String FIND_REGEX = "[^\\d]*\\(" + DOUBLE_REGEX + "\\)[^\\d]*";
      private static final Pattern FIND_PATTERN = Pattern.compile(FIND_REGEX);
      
      private static final Comparator<String> COMPARATOR = Comparator.comparingDouble(
          s -> {
              final Matcher matcher = FIND_PATTERN.matcher(s);
              if (!matcher.find()) {
                  throw new IllegalArgumentException("Cannot compare key: " + s);
              }
              return Double.parseDouble(matcher.group("value"));
          });
      
      private final Map<String, List<String>> map = new TreeMap<>(COMPARATOR);
      

      编辑:如果必须是LinkedHashMap (yours),您可以随时:

      map.putAll(yours);
      yours.clear();
      yours.putAll(map);
      

      【讨论】:

      • 也许让 lambda 主体成为一个方法,这样你就可以编写单元测试了。
      • 公平点,但 lambda 主体刚刚成为 compareCOMPARATOR 方法,因此您始终可以只测试 COMPARATOR 是否正常工作。
      • 它是一个 LinkedHashMap,因为我之前确实关心插入顺序,但现在我需要以这种方式对其进行排序。但是,应该找到使用 TreeMap。不过谢谢,我会试试的。
      • 新问题:我尝试使用您提供的比较器将 LinkedHashMap 直接更改为 TreeMap,但它似乎没有放入一些没有比较器的键值对。知道为什么吗?
      • 不是没有看到一些代码。但是如果这个比较器不能解析一个键,它会抛出一个异常,所以它可能是反射错误。如果您在对性能敏感的地方使用它,您可能也应该缓存解析结果,这样您就不必继续检查正则表达式匹配并为您已经完成的事情加倍值。
      【解决方案3】:

      首先,您不能“排序”LinkedHashMapLinkedHashMap根据插入顺序维护迭代顺序。

      如果您的意思是通过使用原始映射中的值插入创建另一个LinkedHashMap,并且顺序基于排序顺序:您需要注意在初始构造之后添加的任何新条目都将是未排序的。所以你可能想创建一个不可修改的地图。

      对于Comparator 实现,您不需要将其添加到您的自定义类中。只需创建一个比较器就可以了。

      像这样:

      (还没编译,只是给大家看个思路)

      // assume the key is in format of "ABCDE,12345", and you want to sort by the numeric part:
      Map<String, Foo> oldMap = ....; // assume you populated something in it
      Map<String, Foo> sortedMap 
          = new TreeMap((a,b) -> {
                           // here I use split(), you can use regex
                           int aNum = Integer.valueOf(a.split(",")[1]);
                           int bNum = Integer.valueOf(b.split(",")[1]);
                           if (aNum != bNum )  {
                               return aNum - bNum;
                           } else {
                               return a.compareTo(b);
                           });
      sortedMap.addAll(oldMap);
      // now sortedMap contains your entries in sorted order.
      // you may construct a new LinkedHashMap with it or do whatever you want
      

      【讨论】:

      • 嘿,这行得通,但由于某种原因正则表达式不匹配。我会尝试调试它。谢谢!
      • 好的,我解决了正则表达式的问题(没有调用 Matcher.find(),duh),但现在我遇到了无缘无故调用比较器的问题(在它解决之前在(yyy(0.123)) 部分),它破坏了树图。编辑:原来有一个 containsKey 函数由于某种原因调用了比较器 编辑 2:我删除了那个东西,现在它只把一个东西放到地图中,我真的不知道为什么......
      • 提出另一个问题,因为它是一个单独的问题。 TreeMap 使用 ComparatorComparable.compareTo 来检查顺序和相等性。如果没有看到您的 Comparator 实施,我们无法发表任何评论
      • 好吧,事实证明这是因为我将返回结果转换为 int(没有它就无法工作),所以它将双精度值截断为 0,使它们彼此相等,因此不会在第一项之后插入任何内容。谢谢!
      • 这对我来说似乎是一种代码味道。如果您有两个不同的键但具有相同的数字部分,我认为您仍然应该将其视为不同的。比较字符串作为最后的手段应该避免类似的问题。而且,如果有大量数据,或者如果您需要经常更新地图,您可能应该考虑为键创建自定义类的想法。并且使用自定义类作为 Key,您不需要比较器,只需创建一个 TreeMap&lt;CustomKey, Foo&gt;,然后有 CustomKey 实现 Comparable
      猜你喜欢
      • 1970-01-01
      • 2012-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-16
      • 2014-05-09
      • 1970-01-01
      相关资源
      最近更新 更多