'Arrange List in Java to output specific columns

I have 2 csv files which the same data but output of the two files are in different order.

I want to output both lists in the same order.

List csv1 System.out.println(csv1);

Employee, Address, Name, Email

System.out.println(csv2); Output of this List looks like;

Address, Email, Employee Name

How can I sort the lists to print in the column order;

Employee, Name, Email, Address

Note: I can't use integer col(1),col(3) because column 1 in csv1 does not match col1 in csv2

data is read as follows:

 List<String> ret = new ArrayList<>();
BufferedReader r = new BufferedReader(new InputStreamReader(str));
          Stream lines = r.lines().skip(1);

          lines.forEachOrdered(
              line -> {
               line= ((String) line).replace("\"", "");
                 ret.add((String) line);


Solution 1:[1]

I've assumed that you need to parse these two csv files and output in order.

You can use Apache Commons-CSV library for parsing. I've considered below examples

Solution using external library:

test1.csv Address,Email,Employee,Name SecondMainRoad,[email protected],Frank,Michael

test2.csv Employee,Address,Name,Email John,FirstMainRoad,Doe,[email protected]

Sample program

public static void main(String[] args) throws IOException {

    try(Reader csvReader = Files.newBufferedReader(Paths.get
            ("test2.csv"))) {

        // Initialize CSV parser and iterator.
        CSVParser csvParser = new CSVParser(csvReader, CSVFormat.Builder.create()
                .setRecordSeparator(System.lineSeparator())
                .setHeader()
                .setSkipHeaderRecord(true)
                .setIgnoreEmptyLines(true)
                .build());

        Iterator<CSVRecord> csvRecordIterator = csvParser.iterator();
        
        while(csvRecordIterator.hasNext())
        {
            final CSVRecord csvRecord = csvRecordIterator.next();

            final Map<String, String> recordMap = csvRecord.toMap();

            System.out.println(String.format("Employee:%s", recordMap.get("Employee")));
            System.out.println(String.format("Name:%s", recordMap.get("Name")));
            System.out.println(String.format("Email:%s", recordMap.get("Email")));
            System.out.println(String.format("Address:%s", recordMap.get("Address")));
        }
        

    }


}

Standlone Solution:

public class CSVTesterMain {

public static void main(String[] args) {
    
    // I have used string variables to hold csv data, In this case, you can replace with file output lines.
    String csv1= "Employee,Address,Name,Email\r\n" + 
            "John,FirstMainRoad,Doe,[email protected]\r\n" + 
            "Henry,ThirdCrossStreet,Joseph,[email protected]";

    String csv2 = "Address,Email,Employee,Name\r\n" + 
            "SecondMainRoad,[email protected],Michael,Sessner\r\n" + 
            "CrossRoad,[email protected],Vander,John";

    // Map key - To hold header information
    // Map Value - List of lines holding values to the corresponding headers.
    Map<String, List<String>> dataMap = new HashMap<>();

    Stream<String> csv1LineStream = csv1.lines();

    Stream<String> csv2LineStream = csv2.lines();
    
    // We are using the same method to parse different csv formats. We are maintaining reference to the headers
    // in the form of Map key which will helps us to emit output later as per our format.
    populateDataMap(csv1LineStream, dataMap);
    populateDataMap(csv2LineStream, dataMap);
    
    // Now we have dataMap that holds data from multiple csv files. Key of the map is responsible to
    // determine the header sequence.
    
    // Print the output as per the sequence Employee, Name, Email, Address
    System.out.println("Employee,Name,Email,Address");
    dataMap.forEach((header, lineList) -> {
        
        // Logic to determine the index value for each column.
        List<String> headerList = Arrays.asList(header.split(","));
        
        int employeeIdx = headerList.indexOf("Employee");
        int nameIdx = headerList.indexOf("Name");
        int emailIdx = headerList.indexOf("Email");
        int addressIdx = headerList.indexOf("Address");
        
        // Now we know the index value of each of these columns that can be emitted in our format.
        // You can output to a file in your case.
        // Iterate through each line, split and output as per the format.
        lineList.forEach(line -> {
            
            String[] data = line.split(",");
            
            System.out.println(String.format("%s,%s,%s,%s", data[employeeIdx],
                    data[nameIdx],
                    data[emailIdx],
                    data[addressIdx]
                    ));
            
        });
        
        
        
    });
}

private static void populateDataMap(Stream<String> csvLineStream, Map<String, List<String>> dataMap) {
    
    // Populate data map associating the data to respective headers.

    Iterator<String> csvIterator = csvLineStream.iterator();

    // Fetch header. (In my example, I am sure that my first line is always the header).
    String header = csvIterator.next();

    if(! dataMap.containsKey(header))
        dataMap.put(header, new ArrayList<>());
    
    // Iterate through the remaining lines and populate data map.
    while(csvIterator.hasNext())
        dataMap.get(header).add(csvIterator.next());
    
}

}

Solution 2:[2]

Here I am using Jackson dataformat library to parse the csv files.

Dependency

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-csv</artifactId>
    <version>2.13.2</version>
</dependency>

File 1

employee, address, name, email
1, address 1, Name 1, [email protected]
2, address 2, Name 2, [email protected]
3, address 3, Name 3, [email protected]

File 2

address, email, employee, name
address 4, [email protected], 4, Name 4
address 5, [email protected], 5, Name 5
address 6, [email protected], 6, Name 6

Java Program

Here EmployeeDetails is a POJO class. And it is expected that the location of the csv files is passed as an argument.

import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class EmployeeDataParser {

    public static void main(String[] args) {
        File directoryPath = new File(args[0]);
        File filesList[] = directoryPath.listFiles();
        List<EmployeeDetails> employeeDetails = new ArrayList<>();

        EmployeeDataParser employeeDataParser=new EmployeeDataParser();
        for(File file : filesList) {
            System.out.println("File path: "+file.getAbsolutePath());
            employeeDataParser.readEmployeeData(employeeDetails, file.getAbsolutePath());
        }

        System.out.println("number of employees into list: " + employeeDetails.size());
        employeeDataParser.printEmployeeDetails(employeeDetails);
    }

    private List<EmployeeDetails> readEmployeeData(List<EmployeeDetails> employeeDetails,
                                                          String filePath){
        CsvMapper csvMapper = new CsvMapper();
        CsvSchema schema = CsvSchema.emptySchema().withHeader();

        ObjectReader oReader = csvMapper.readerFor(EmployeeDetails.class).with(schema);

        try (Reader reader = new FileReader(filePath)) {
            MappingIterator<EmployeeDetails> mi = oReader.readValues(reader);

            while (mi.hasNext()) {
                EmployeeDetails current = mi.next();
                employeeDetails.add(current);
            }
        } catch (IOException e) {
            System.out.println("IOException Caught !!!");
            System.out.println(e.getStackTrace());
        }

        return employeeDetails;
    }

    private void printEmployeeDetails(List<EmployeeDetails> employeeDetails) {
        System.out.printf("%5s %10s %15s %25s", "Employee", "Name", "Email", "Address");
        System.out.println();
        for(EmployeeDetails empDetail:employeeDetails){
            System.out.format("%5s %15s %25s %15s", empDetail.getEmployee(),
                    empDetail.getName(),
                    empDetail.getEmail(),
                    empDetail.getAddress());

            System.out.println();
        }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Noel John