【问题标题】:How do I sort numbers from a text file using Java?如何使用 Java 对文本文件中的数字进行排序?
【发布时间】:2021-11-15 17:38:15
【问题描述】:

我尝试了 StackOverflow 上其他线程建议的多个解决方案,但我没有找到解决方案。我正在尝试使用 Java 读取 .txt 文件并从最大到最小对内容进行排序。这是我的 .txt 文件包含的内容:

16° C
15° C
18° C
13° C
17° C
19° C
21° C
20° C
16° C

这是我尝试过的:

import java.io.*;
import java.util.*;

public class temperatur {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = null;
        PrintWriter outputStream = null;
        ArrayList<String> rows = new ArrayList<String>();

        try {
            reader  = new BufferedReader(new FileReader("temp.txt"));
            outputStream = new PrintWriter(new FileWriter("tempout.txt"));

            String file;
            while ((file = reader .readLine()) != null) {
                rows.add(file);
            }
            
            Collections.sort(rows);
            String[] strArr= rows.toArray(new String[0]);
            for (String cur : strArr)
                outputStream.println(cur);
        } finally {
            if (reader != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

【问题讨论】:

  • 你试过什么?你能展示你的代码吗?
  • 那你有什么问题?文件阅读?排序?你能展示一下你目前的方法吗?
  • 你能添加输出文件的样子吗?
  • 可以跳过创建额外String[] 的额外步骤。只需遍历您的 rows 列表。
  • 另外,您可能会按字母数字排序 - 将“1°”、“5°”和“100°”添加到您的输入文件中,看看您是否获得了预期的结果。并查看stackoverflow.com/a/1694770/13447 以反转订单。

标签: java sorting txt


【解决方案1】:

这会读取temp.text 并拆分每一行以获得数字部分(假设它总是在° 符号之前)添加到tempList 中,然后对其进行排序。然后通过将排序列表与输入文件中给出的字符串的其余部分连接起来,将排序列表写入输出文件。

import java.io.*;
import java.util.*;

public class temperatur{
public static void main(String[] args) throws IOException {
    File file = new File("temp.txt");
    List<Double> tempList = new ArrayList();
    BufferedReader br = new BufferedReader(new FileReader(file));
    String st;
    while ((st = br.readLine()) != null) {
        String[] temp = st.split("°");
        tempList.add(Double.parseDouble(temp[0]));
    }
    Collections.sort(tempList);
    Collections.reverse(tempList);
    
    //Write into a new file 
    FileWriter file2 = new FileWriter("tempout.txt");
    String sb = "";
    for (double a : tempList) {
        sb += a + "°" + " C\n";
    }
    file2.write(sb);
    file2.close();
    
  }
}

tempout.txt

21.0° C
20.0° C
19.0° C
18.0° C
17.0° C
16.0° C
16.0° C
15.0° C
13.0° C

【讨论】:

    【解决方案2】:

    以下示例使用 java.nio 等较新的技术而不是 java.io 进行文件系统操作和流数据:

    public static void main(String[] args) throws IOException {
        // define the suffix needed to replace and append
        String suffix = "° C";
        // create a java.nio.Path from it
        Path temperaturesPath = Paths.get(temperaturesFile);
        // check if it exists
        if (Files.exists(temperaturesPath, LinkOption.NOFOLLOW_LINKS)) {
            // then check if it actually is a regular file
            if (Files.isRegularFile(temperaturesPath, LinkOption.NOFOLLOW_LINKS)) {
                // and check if the file is readable
                if (Files.isReadable(temperaturesPath)) {
                    // then read all its lines
                    List<String> sortedTemperatures = Files.readAllLines(temperaturesPath)
                                                    // stream them
                                                    .stream()
                                                    // map the temperature values to Integers
                                                    .map(line -> Integer.parseInt(line.replace(suffix, "")))
                                                    // reverse-sort them
                                                    .sorted(Comparator.reverseOrder())
                                                    // map the sorted Integers back to a String with the suffix
                                                    .map(tempVal -> String.format("%d%s", tempVal, suffix))
                                                    // and collect the resultin Strings in a List
                                                    .collect(Collectors.toList());
                    // finally print the elements of the result list
                    sortedTemperatures.forEach(System.out::println);
                }
            }
        }
    }
    

    使用有效路径中的有效文件执行此代码的结果是:

    21° C
    20° C
    19° C
    18° C
    17° C
    16° C
    16° C
    15° C
    13° C
    

    【讨论】:

    • 很好,@ArvindKumarAvinash... 相应地更改了实现,无论如何都是一个不好的方法。
    【解决方案3】:

    扩展我的评论,这里是如何对rows 中已有的行进行排序的示例。这是假设您想保留原始行而不是重建它们。

    解析和排序

    最好使用一个类来保存行的内容和数值,例如:

    //simplified, add setters, getters etc.
    class Line {
      String content;
      double temp;
    }
    

    并在阅读行时构建它:

    List<Line> rows = ...
    String lineContent;
    while ((lineContent= reader .readLine()) != null) {
       double temp = Double.parseDouble(lineContent.split("°")[0]);
       rows.add(new Line(lineContent, temp));
    }
    

    然后排序:

    Collections.sort(rows, Comparator.comparing(Line::getTemp).reversed());

    直接对字符串进行排序

    字符串通过比较字符进行排序,因此"10" 将被视为小于"2"。因此我们需要使用一个“技巧”:

    • 先按长度排序,所以 2 小于 10
    • 然后按词法排序
    Collections.sort(rows, Comparator.comparing(String::length)
                                     .thenComparing(Function.identity())
                                     .reversed());
    

    请注意,如果数字可能为负数或具有不同的格式(即不同长度的分数、不同数量的空格、行中的附加数据等),则会中断。在这些情况下,比较器需要更复杂,复杂度越高,使用“解析和排序”方法就越容易。

    供您参考,这里有一个比较器,它应该能够对支持符号(+ 和 -)的相同格式(相同数量的小数位数等)的字符串进行排序:

    Collections.sort(rows, (String left, String right) -> {
            char c1Left = left.charAt(0);
            char c1Right = right.charAt(0);
            
            int direction = -1; //1 for ascending
            
            //negative numbers are smaller than 0 or positive numbers
            int result = Integer.compare(c1Left == '-' ? -1 : 0, c1Right == '-' ? -1 : 0);
            if( result != 0) {
                return result * direction;
            }
            
            //at this point, both numbers are either both positive or both negative
            //for negative numbers we need to reserve direction since we'll only compare "absolute values"
            if( c1Right == '-' ) {
                direction *= -1;
            }
            
            String subLeft = Character.isDigit(c1Left) ? left : left.substring(1);
            String subRight = Character.isDigit(c1Right) ? right : right.substring(1);
            
            //shorter numbers are smaller than longer numbers (takes care of cases like 2 vs 10 or 3.1 vs 21.0)
            result = Integer.compare(subLeft.length(), subRight.length());
            if( result != 0) {
                return result * direction;
            }
            
            //sign and length are equal, the rest is a simple character comparison
            result = subLeft.compareTo(subRight);
            
            return result * direction;
        });
    

    【讨论】:

    • 非常好的建议:最好使用一个类来保存行的内容和数值
    【解决方案4】:

    你应该解析你的数据,例如

    static Pattern temperatureRegex = Pattern.compile("^([0-9]+)° C$");
    
    private static int parseTemperature(String s) {
        return of(temperatureRegex.matcher(s))  // get a matcher
                .filter(Matcher::find)          // must find
                .map(m -> parseInt(m.group(1))) // to integer
                .orElseThrow();                 // or exception
    }
    

    然后,只需使用 sort 读写行映射

    write(Paths.get("/home/josejuan/tmp/Tout.txt"),
            readAllLines(Paths.get("/home/josejuan/tmp/T.txt")).stream()
                    .sorted(Comparator.comparingInt(SortFile::parseTemperature)).collect(toList()));
    

    (除了完整的代码)

    package com.computermind.sandbox.fileprocessing;
    
    import java.io.IOException;
    import java.nio.file.Paths;
    import java.util.Comparator;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import static java.lang.Integer.parseInt;
    import static java.nio.file.Files.readAllLines;
    import static java.nio.file.Files.write;
    import static java.util.Optional.of;
    import static java.util.stream.Collectors.toList;
    
    public class SortFile {
    
        static Pattern temperatureRegex = Pattern.compile("^([0-9]+)° C$");
    
        private static int parseTemperature(String s) {
            return of(temperatureRegex.matcher(s))  // get a matcher
                    .filter(Matcher::find)          // must find
                    .map(m -> parseInt(m.group(1))) // to integer
                    .orElseThrow();                 // or exception
        }
    
        public static void main(String... args) throws IOException {
            write(Paths.get("/home/josejuan/tmp/Tout.txt"),
                    readAllLines(Paths.get("/home/josejuan/tmp/T.txt")).stream()
                            .sorted(Comparator.comparingInt(SortFile::parseTemperature)).collect(toList()));
        }
    
    }
    

    【讨论】:

    • 好答案!如果某些温度有小数部分,我会使用parseDouble 来避免异常。
    猜你喜欢
    • 2022-01-01
    • 2019-05-03
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 2018-05-20
    • 2011-04-24
    相关资源
    最近更新 更多