0

I am trying to figure out why my date sorting isn't working.

I want to sort a CSV file by some select columns(Strings) then by the date column. However it is not sorting the date correctly - its appears its just ordering it by the first part of the date (25/12/2018) and not the exact date.

public class MultiColumnCsvSort
{
private static final String COLUMN_SEPARATOR = ",";

public static void main(String[] args) throws Exception
{
    InputStream inputStream = new FileInputStream("order_lines_file.csv");
    List<List<String>> lines = readCsv(inputStream);

    // Create a comparator that sorts primarily by column 0,
    // and if these values are equal, by column 2
    Comparator<List<String>> comparator = createComparator(2,1,5);
    Collections.sort(lines, comparator);


    OutputStream outputStream = new FileOutputStream("output.csv");
    String header = "order id, sku, store, location, quantity, date";
    writeCsv(header, lines, outputStream);        
}
private static List<List<String>> readCsv(
    InputStream inputStream) throws IOException
{
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(inputStream));
    List<List<String>> lines = new ArrayList<List<String>>();

    // Skip header
    String line = reader.readLine();

    while (true)
    {
        line = reader.readLine();
        if (line == null)
        {
            break;
        }
        List<String> list = Arrays.asList(line.split(COLUMN_SEPARATOR));
        lines.add(list);
    }
    return lines;
}
private static void writeCsv(
    String header, List<List<String>> lines, OutputStream outputStream) 
    throws IOException
{
    Writer writer = new OutputStreamWriter(outputStream);
    writer.write(header+"\n");
    for (List<String> list : lines)
    {
        for (int i = 0; i < list.size(); i++)
        {
            writer.write(list.get(i));
            if (i < list.size() - 1)
            {
                writer.write(COLUMN_SEPARATOR);
            }
        }
        writer.write("\n");
    }
    writer.close();
}

private static <T extends Comparable<? super T>> Comparator<List<T>> 
    createComparator(int... indices)
{
    return createComparator(MultiColumnCsvSort.<T>naturalOrder(), indices);
}

private static <T extends Comparable<? super T>> Comparator<T>
    naturalOrder()
{
    return new Comparator<T>()
    {
        @Override
        public int compare(T t0, T t1)
        {
            return t0.compareTo(t1);
        }
    };
}
private static <T> Comparator<List<T>> createComparator(
    final Comparator<? super T> delegate, final int... indices)
{
    return new Comparator<List<T>>()
    {
        @Override
        public int compare(List<T> list0, List<T> list1)
        {   
            for (int i = 0; i < indices.length; i++)
            {
                T element0 = list0.get(indices[i]);
                T element1 = list1.get(indices[i]);
                        int n = delegate.compare(element0, element1);
                        if (n != 0)
                        {
                            return n;
                        }
            }
            return 0;
        }
    };
}

}

Which I took from this post:

How to sort csv file by two columns in java?

However the output looks like the following when I know there are rows with dates between those values: current sorted file

Thelouras
  • 852
  • 1
  • 10
  • 30
  • Yes, the `naturalOrder` comparator sorts purely on the String. You will need to convert the input column from the text "25/12/2018" to a suitable Java class, and then you can do the comparison. – KevinO Mar 19 '19 at 02:45
  • @KevinO Could you please show me how I could do this in my code? – WillEyedowin Mar 20 '19 at 03:04

1 Answers1

0

YYYY-MM-DD (ISO 8601 format)

ordering it by the first part of the date (25/12/2018) and not the exact date.

So morph the string to standard ISO 8601 format (YYYY-MM-DD). Values sorted alphabetically will also be chronological.

Parse input strings

Define a formatting pattern to match your inputs.

String input = "25/12/2018" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) ;
LocalDate ld = LocalDate.parse( input , f ) ;

Of course you should cache the DateTimeFormatter object in your real code. Be aware that the java.time classes are thread-safe, and use the immutable objects pattern.

Generate output strings

The java.time classes use the standard ISO 8601 formats by default when generating/parsing strings. So no need to specify a formatting pattern.

String output = ld.toString() ;  // Outputs standard format: YYYY-MM-DD
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • Thank you for the suggestion - are you able to show me where I should put this in my code? Played around with it a little but got stuck. – WillEyedowin Mar 20 '19 at 00:11