如何使用 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"
。因此我们需要使用一个“技巧”:
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 对文本文件中的数字进行排序?的主要内容,如果未能解决你的问题,请参考以下文章