如何使用 Java 对文本文件中的数字进行排序?

Posted

技术标签:

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

我尝试了 *** 上其他线程建议的多个解决方案,但我没有找到解决方案。我正在尝试使用 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°”添加到您的输入文件中,看看您是否获得了预期的结果。并查看***.com/a/1694770/13447 以反转订单。 【参考方案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 来避免异常。

以上是关于如何使用 Java 对文本文件中的数字进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

linux中如何对一个文本内容进行排序呢

使用 Java 中的 Scanner 类读取 .txt 文件

通过Qt中的程序对文本文件进行排序

基于多个列对包含numpy文本数组中的数字的列进行排序

JAVA读取文件 排序 写出文件

linux中如何对一个文本内容进行排序呢