2

I have tried multiple solutions suggested by other threads on StackOverflow, but I haven't found a solution. I'm trying to read a .txt file and sort the content from largest to smallest, using Java. This is what my .txt file contains:

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

Here is what I've tried:

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();
            }
        }
    }
}
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
virreoh
  • 21
  • 3
  • 1
    What have you tried? Could you show your code? – Héctor Sep 22 '21 at 08:58
  • 1
    So what are you having trouble with? The file-reading? The sorting? Can you show your current approach? – maloomeister Sep 22 '21 at 08:58
  • Can you add what the output file looks like? – Scratte Sep 22 '21 at 09:02
  • I can see 2 approaches to sorting: 1) parse the lines into numbers, then sort (keep pairs of line and parsed number) or 2) sort using string length first and lexicographical order second (only works if numbers can't get negative) – Thomas Sep 22 '21 at 09:04
  • 1
    The extra step where you create an additional `String[]` can be skipped. Simply iterate over your `rows` list. – maloomeister Sep 22 '21 at 09:06
  • 1
    Also, you're likely sorting alphanumerically - add "1°", "5°" and "100°" to your input file and see if you get the expected results. And look at https://stackoverflow.com/a/1694770/13447 for reversing the order. – Olaf Kock Sep 22 '21 at 09:08
  • [Collections.sort](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Collections.html#sort(java.util.List)) "Sorts the specified list into ascending order". If you need them in descending order instead, you'll need to provide with a [Comparator](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Comparator.html). – Scratte Sep 22 '21 at 09:08
  • Convert ArrayList to ArrayList then try to convert String to Numeric value as below, str.replaceAll("[^\\d.]", ""); – sunleo Sep 22 '21 at 09:14

4 Answers4

1

This reads through temp.text and splits each line to get the numeric part (given that it is always before the ° symbol) to add into an tempList which is then sorted. The sorted list is then written into the output file by joining it with the rest of the string as given in the input file.

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

vnk
  • 1,060
  • 1
  • 6
  • 18
1

Here's an example that uses newer technologies like java.nio instead of java.io for file system operations as well as streaming data:

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);
            }
        }
    }
}

The result of executing this code with a valid file in a valid path is:

21° C
20° C
19° C
18° C
17° C
16° C
16° C
15° C
13° C
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • 1
    Very good point, @ArvindKumarAvinash... Changed implementation accordingly, was a bad approach anyway. – deHaar Oct 10 '21 at 18:42
1

Expanding on my comment, here are examples of how to sort the lines you already have in rows. This is assuming you want to keep the original lines instead of reconstructing them.

parse and sort

Ideally use a class to hold the line's content and the numerical value, e.g.:

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

And build it when reading the lines:

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

Then sort:

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

Sort the strings directly

Strings are sorted by comparing characters and thus "10" would be considered smaller than "2". Thus we need to use a "trick":

  • Sort by length first so 2 is smaller than 10
  • Then sort lexically
Collections.sort(rows, Comparator.comparing(String::length)
                                 .thenComparing(Function.identity())
                                 .reversed());

Note that this breaks if numbers can get negative or have a different format (i.e. fractions of differing lengths, different number of spaces, additional data in the lines etc.). The compators would need to be more complex in those cases and the higher the complexity the easier it would be to use the "parse and sort" approach.

For your reference, here's a comparator that should be able to sort strings of the same format (same number of fraction digits, etc.) supporting signs (+ and -):

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;
    });
Thomas
  • 87,414
  • 12
  • 119
  • 157
1

You should parse your data, e.g.

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
}

then, simply read and writes lines mapping with 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()));

(Aside full code)

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()));
    }

}
josejuan
  • 9,338
  • 24
  • 31