【问题标题】:How to sort a collection of files names numerically instead of alphabetically?如何按数字而不是字母顺序对文件名集合进行排序?
【发布时间】:2019-05-05 08:56:39
【问题描述】:

我目前正在使用SortedSet<String> fileNames = new TreeSet<String>()对文件名进行排序,但它们并没有像我想要的那样排序。

这正是我所做的:

File folder = new File(PATH);
File[] listOfFiles = folder.listFiles();
SortedSet<String> fileNames = new TreeSet<String>;
for (int i = 0; i < listOfFiles.length; i++) 
{
     if (listOfFiles[i].isFile())
     {
        fileNames.add(listOfFiles[i].getName());
     }
}

输出:

X_1(1).PNG
X_1(2).PNG 
X_1(3).PNG 
X_10(1).PNG
X_10(2).PNG
X_10(3).PNG
X_100(1).PNG
X_100(2).PNG
X_100(3).PNG 

期望的输出:

X_1(1).PNG
X_1(2).PNG
X_1(3).PNG
X_2(1).PNG
X_2(2).PNG
X_2(3).PNG

【问题讨论】:

  • 您似乎需要一个自定义的Comparator,但如果没有一些代码向我们展示您为获得当前输出所做的工作,您很难为您提供帮助。
  • 我只是迭代一个文件夹,获取文件名并将它们添加到 SortedSet 中,仅此而已。
  • 这里的输入是什么?

标签: java string sorting collections


【解决方案1】:

将此 Comparator 参数放入 TreeSet 构造函数中:

Comparator<String> stringComparator = (o1, o2) -> {
  int o1FirstNum = Integer.parseInt(o1.substring(o1.indexOf('_') + 1, o1.indexOf('(')));
  int o2FirstNum = Integer.parseInt(o2.substring(o2.indexOf('_') + 1, o2.indexOf('(')));

  if (o1FirstNum == o2FirstNum) {
    int o1SecondNum = Integer.parseInt(o1.substring(o1.indexOf('(') + 1, o1.indexOf(')')));
    int o2SecondNum = Integer.parseInt(o2.substring(o2.indexOf('(') + 1, o2.indexOf(')')));
    return o1SecondNum - o2SecondNum;
  }

  return o1FirstNum - o2FirstNum;
};

SortedSet<String> fileNames = new TreeSet<String>(stringComparator);

【讨论】:

  • 问题在于,带有相同 X 但括号中数字不同的文件将从Set 中删除,因为它们将被视为重复文件
  • 你说得对,可以通过扩展Compatrator对象的定义来处理
【解决方案2】:

这个比较器应该可以解决你的问题。

public class Test {

    public static void main(String... args) {
        String[] list = {"X_1(1).PNG", "X_1(2).PNG", "X_1(3).PNG", "X_10(1).PNG", "X_10(2).PNG", "X_10(3).PNG", "X_100(1).PNG", "X_100(2).PNG", "X_100(3).PNG"};

        SortedSet<String> fileNames = new TreeSet<>(Test::compare);
        fileNames.addAll(Arrays.asList(list));

        fileNames.forEach(System.out::println);
    }

    private static int compare(String first, String second) {
        int firstNumber = Integer.parseInt(first.substring(first.indexOf('_') + 1, first.indexOf('(')));
        int secondNumber = Integer.parseInt(second.substring(first.indexOf('_') + 1, second.indexOf('(')));

        int difference = firstNumber - secondNumber;

        if (difference != 0) {
            return difference;
        }

        firstNumber = Integer.parseInt(first.substring(first.indexOf('(') + 1, first.indexOf(')')));
        secondNumber = Integer.parseInt(second.substring(first.indexOf('(') + 1, second.indexOf(')')));

        return firstNumber - secondNumber;
    }

}

【讨论】:

    【解决方案3】:

    您正在寻找一种自然的排序比较器,它可以理解数字序列。

    您可以使用以下之一:

    第一个可以用作 maven 依赖项,但是由于 Comparator 没有实现 Comparator&lt;String&gt;(而只是 Comparator),因此您最好发出拉取请求来执行此操作。

    最后一个可能是最好的,因为它是 ASL 2.0。

    顺便说一句,你应该在 TreeSet 中继续使用 File(或 Path)并传入一个比较器:

    Comparator<String> naturalSortComparator = ...;
    TreeSet<File> files = new TreeSet<>(Comparators.comparing(File::getName, naturalSortComparator));
    

    这将使用naturalSortComparator按名称对File条目进行排序。

    【讨论】:

      猜你喜欢
      • 2011-03-30
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      • 1970-01-01
      • 2017-10-10
      • 1970-01-01
      相关资源
      最近更新 更多