【问题标题】:Sort half of a String ArrayList based on a substring of each string根据每个字符串的子字符串对字符串 ArrayList 的一半进行排序
【发布时间】:2020-02-20 21:46:32
【问题描述】:

我有一个大小的字符串数组列表,例如

[12、10L、10、10R、10S、10L]

输出应该是

[10S、10R、10L、10、12]

所以基本上尺寸必须首先按数字排序 - (1,2,3,4,5 ...等)然后按字母。

我设法让数字排序,所以我上面输入的当前输出是

10L、10、10R、10S、10L、12

如果缺少一个字母,那么它是最大的(见上面的输出 - 10 在 10L 之后 - 10S

我应该如何编写一个允许我这样做的比较器?

考虑一个输入数组,大小。该数组包含 AB 格式的产品尺寸,其中:

A是强制整数 B是[S,R,L]中的可选字符 大小必须先按A从小到大排序,再按S按B排序

【问题讨论】:

  • 很有可能正确的方法是将每个String 解析为一个专用类,该类表示它是一个扩展Comparable 以提供正确的compare 方法。另外,为什么 S 应该小于 R 并且 R 应该小于 L?按字母顺序正好相反,那么这里的规则是什么?
  • 这些是规则,Small、Regular 和 Large,我应该提到它的衣服,这就是为什么它们会这样
  • 在上面的例子中,“12S”会落在哪里?在“10”和“12”之间?还是在“10L”和“10”之间?
  • 考虑一个输入数组,大小。此数组包含格式为 AB 的产品尺寸,其中: A 是强制整数 B 是 [S,R,L] 中的可选字符 尺寸必须首先按 A 从小到大排序,然后按 S 的顺序按 B
  • @Mivakes:编写一个实现Comparable<Size>Size 类可能是最干净的。然后去掉List<String>,改用List<Size>

标签: java string sorting arraylist comparator


【解决方案1】:

如果它适用于您的测试用例,请尝试此方法。如果需要,我们可以随时对其进行改进。 (添加了辅助方法)

List<String> list = new ArrayList<>(Arrays.asList("12","10L","10","10R","10S","10L","14L","14","8","12S"));
List<String> orderArray = new ArrayList<>(Arrays.asList("S", "R", "L"));

List<String> sortedList = list.stream()
            .sorted(Comparator.comparing(str -> Integer.parseInt(((String)str).replaceAll("[A-Z]*","")))
                    .thenComparing(str -> getAnInt(orderArray, (String) str)))
            .distinct()
            .collect(Collectors.toList());

System.out.println(sortedList);

private int getAnInt(List<String> orderArray, String str) {
    int i = orderArray.indexOf(str.substring(str.length() - 1));
    if (i == -1) return Integer.MAX_VALUE;
    return i;
}

输出:[8, 10S, 10R, 10L, 10, 12S, 12, 14L, 14]

如果您不想使用流:

List<String> list = new ArrayList<>(Arrays.asList("12","10L","10","10R","10S","10L","14L","14","8","12S"));
List<String> orderArray = new ArrayList<>(Arrays.asList("S", "R", "L"));

list.sort(new Comparator<String>() {
        @Override
        public int compare(String lhs, String rhs) {
            int lInt = Integer.parseInt(lhs.replaceAll("[A-Z]*", ""));
            int rInt = Integer.parseInt(rhs.replaceAll("[A-Z]*", ""));
            if (lInt != rInt) {
               return lInt - rInt;
            } else {
                return getAnInt(orderArray, lhs) - getAnInt(orderArray, rhs);
            }
        }
    });

System.out.println(list);

【讨论】:

  • 它只是在 java 7 中不起作用的流,否则基本思想是相同的。您可以使用循环而不是流
  • @Mivakes 更新了不使用流的答案。试试看
  • Arrays.asList 确实已经返回了 List。无需通过new ArrayList(…) 复制列表。此外,不使用 Streams 并不意味着您必须通过匿名内部类实现 Comparator。并且不要使用减号来实现Comparator,因为减号会溢出。使用Integer.compare(…,…)。您可以通过为第一个 lambda 声明显式参数类型来避免类型转换,comparingInt 在这里可能更有效:Comparator.comparingInt((String str) -&gt; Integer.parseInt(str.replaceAll("[A-Z]*",""))) .thenComparingInt(str -&gt; getAnInt(orderArray, str))
  • 此外,由于getAnInt 假定数字后有一个字母的固定格式,上一步可能使用与Comparator.comparingInt((String str) -&gt; Integer.parseInt(str.substring(0, str.length() - 1))) 相同的假设,而不是昂贵的正则表达式替换操作。顺便说一句,getAnInt 可以像return orderArray.indexOf(str.substring(str.length() - 1)) + Integer.MIN_VALUE; 一样简单地实现,它将返回具有所需关系的数字。
【解决方案2】:

我假设finalList 列表有排序数据。

10L, 10, 10R, 10S, 10L, 12

使用正则匹配整数,合并alphanumericsnumbers的列表。

在你的排序列表上,运行这个

List<String> numberList= new ArrayList<String>(); // store number list
List<String> sizeList= new ArrayList<String>(); // store alphanumerics
for(String value: finalList){

  if(!value.matches("[0-9]+")){  // if contains characters
     sizeList.add(value);
   }
   else{
        numberList.add(value);
  }
}

sizeList.addAll(numberList); 

sizeList 有你需要的东西

【讨论】:

  • 我不确定这是否正确,因为这可能是由于我的错误解释,我应该复制并粘贴我在编辑上面所做的它只是以与以前相同的方式返回列表
  • I managed to get the numbers to sort, so my current output for the input above is 10L, 10, 10R, 10S, 10L, 12 将此结果存储在 finalList 中,即 List
  • 你在检查 sizeList 吗?它将具有排序列表
  • @Mivakes 让我修复它...给我 2 分钟
  • 我修复了它,也测试了输出。我更改了正则表达式,它给出了正确的输出。实际上,以前,我正在检查数字是否为字母数字..10 是有效的字母数字字符以及有效的整数,这就是为什么它总是在第一次检查中进行。
猜你喜欢
  • 2015-09-11
  • 2015-08-13
  • 2021-03-27
  • 2021-11-09
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-07
相关资源
最近更新 更多