首页 > 解决方案 > 在java中按列标题对二维列表进行排序

问题描述

我正在做一个可以读取和写入 CSV 的简单数据框,并包含按列排序的排序功能。如何通过输入列标题对正确的列进行排序,并从排序中排除列标题行?

这是 CSV 文件的示例数据:

Name,Age,Salary
Lim,20,2000
Tan,20,3000
Mah,19,2500
Roger,10,4000

我已经声明了我的 2D 列表,数据将如下所示:

List<List<String>> COLUMNDATA = new ArrayList();
COLUMNDATA = [[Name, Age, Salary], [Lim, 20, 2000], [Tan, 20, 3000], [Mah, 19, 2500], [Roger, 10, 4000]]

我想通过传入列标题对正确的列进行排序,并且列标题行不包含在排序中。例如:

COLUMNDATA.sort(“Age”)

所以它会变成这样:

Name,Age,Salary
Roger,10,4000
Mah,19,2500
Lim,20,2000
Tan,20,3000

我用过Comparatorand Collections.sort,现在卡住了。如何实现我想要的功能?

final Comparator<List<String>> comparator = new Comparator<List<String>>() {
    @Override
    public int compare(List<String> object1, List<String> object2) {
        return object1.get(1).compareTo(object2.get(1));
    }
};

Collections.sort(COLUMNDATA, comparator);
for (List<String> list : COLUMNDATA) {
    System.out.println(list);
}

标签: javalistsortingcolumnsorting

解决方案


这是按照您的要求进行操作的方法。一旦定义了比较器,只需sublist从列表 1 开始排序,跳过标题。由于它是原始列表的视图,它仍然对所需项目进行排序。

首先在要排序的字段上制作字段映射。如果你愿意,你可以不区分大小写。对于此示例,大小写很重要。

static Map<String, Integer> sortingFields = new HashMap<>();
static {
    List<String> columns = List.of("Name", "Age", "Salary");
    for (int i = 0; i < columns.size(); i++) {
        sortingFields.put(columns.get(i), i);
    }
}

创建列表列表。

List<List<String>> data = new ArrayList<>();
data.add(new ArrayList<>(List.of("Name" ,"Age", "Salary")));
data.add(new ArrayList<>(List.of("Lim", "20", "4000")));
data.add(new ArrayList<>(List.of("Tan",   "20", "3000")));
data.add(new ArrayList<>(List.of("Mah",   "19", "2500")));
data.add(new ArrayList<>(List.of("Roger", "10", "3500")));

现在调用排序和打印

sort("Age", data);
data.forEach(System.out::println);

印刷

[Name, Age, Salary]
[Roger, 10, 3500]
[Mah, 19, 2500]
[Lim, 20, 4000]
[Tan, 20, 3000]

这是排序方法。

public static void sort(String Column, List<List<String>> data) {
        // use the column string to select the column number to sort.
        Comparator<List<String>> comp =
                (a, b) -> a.get(sortingFields.get(column))
                        .compareTo(b.get(sortingFields.get(column)));

  data.subList(1,data.size()).sort(comp);
}


这就是我建议您组织数据并进行排序的方式。

首先创建一个类,如图所示。然后使用数据用类的实例填充列表。然后只需指定要排序的 getter。您可以根据需要添加任意数量的附加字段及其 getter。

原因是它允许混合类型存储在同一个对象中并且仍然可以排序。如果您对 a 进行排序String number,它将排序lexcally而不是numerically. 除非您转换为整数,否则这将是一个问题(要查看此内容,请更改4000400上面的薪水并对其进行排序)。但是,如果要对名称进行排序,则需要一个不同的比较器,因为将非 int 转换为 int 会引发异常。这一切都可以在一定程度上得到缓解,但它不像创建一个类那么简单。

通过简单地将方法引用更改为所需getter的,您可以List对任何字段进行排序。如果不存在 getter,并且该字段是公共的(不推荐),您可以使用 lambda。

public class SortingByColumn {
    
    public static void main(String[] args) {
        
        List<Person> data = new ArrayList<>();
        data.add(new Person("Lim", 20, 2000));
        data.add(new Person("Tan", 20, 3000));
        data.add(new Person("Mah", 19, 2500));
        data.add(new Person("Roger", 10, 4000));
        
        List<Person> sorted = data.stream()
                .sorted(Comparator.comparing(Person::getAge))
                .collect(Collectors.toList());
        System.out.printf("%10s  %10s  %10s%n", "Name","Age","Salary");
        sorted.forEach(System.out::println);
    }
    
    static class Person {
        private String name;
        private int age;
        private int salary;
        
        public Person(String name, int age, int salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
        
        public String getName() {
            return name;
        }
        
        public int getAge() {
            return age;
        }
        
        public int getSalary() {
            return salary;
        }
        
        @Override
        public String toString() {
            return String.format("%10s  %10s  %10s", name, age,
                    salary);
        }
    }
}

印刷

      Name         Age      Salary
     Roger          10        4000
       Mah          19        2500
       Lim          20        2000
       Tan          20        3000

推荐阅读