java中按列标题对2d列表排序

v09wglhw  于 2021-06-30  发布在  Java
关注(0)|答案(5)|浏览(413)

我正在做一个简单的Dataframe,可以读写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

我用过 Comparator 以及 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);
}
cnjp1d6j

cnjp1d6j1#

我提出不使用 List ,我认为那是有用的 class 相对的名字更清楚。在本课程中,您可以定义所需的比较器。

public class Foo {
    public static void main(String... args) throws IOException {
        List<DataLine> data =
                readFile(Path.of("e:/data.csv"), StandardCharsets.UTF_8);
        List<DataLine> sortedByName = DataLine.Field.NAME.sort(data);
        List<DataLine> sortedByAge = DataLine.Field.AGE.sort(data);
        List<DataLine> sortedBySalary = DataLine.Field.SALARY.sort(data);
    }

    public static List<DataLine> readFile(Path path, Charset charset)
            throws IOException {
        try (Scanner scan = new Scanner(path, charset)) {
            scan.useDelimiter("[,\n]");
            scan.nextLine();    // skip header

            List<DataLine> data = new ArrayList<>();

            while (scan.hasNext()) {
                String name = scan.next();
                int age = scan.nextInt();
                int salary = scan.nextInt();
                data.add(new DataLine(name, age, salary));
            }

            return data;
        }
    }

    public static final class DataLine {

        enum Field {
            NAME(Comparator.comparing(one -> one.name)),
            AGE(Comparator.comparingInt(one -> one.age)),
            SALARY(Comparator.comparingInt(one -> one.salary));

            private final Comparator<DataLine> comparator;

            Field(Comparator<DataLine> comparator) {
                this.comparator = comparator;
            }

            public final List<DataLine> sort(List<DataLine> data) {
                return data.stream()
                        .sorted(comparator)
                        .collect(Collectors.toList());
            }
        }

        private final String name;
        private final int age;
        private final int salary;

        public DataLine(String name, int age, int salary) {
            this.name = name;
            this.age = age;
            this.salary = salary;
        }
    }
}
lzfw57am

lzfw57am2#

你可以加入这个名单 sorted 从第二排开始,然后 collect 新列表如下:

public static void main(String[] args) {
    List<List<String>> columnData = List.of(
            List.of("Name", "Age", "Salary"),
            List.of("Lim", "20", "2000"),
            List.of("Tan", "20", "3000"),
            List.of("Mah", "19", "2500"),
            List.of("Roger", "10", "4000"));

    List<List<String>> sortedData1 = sortByColumn(columnData, "Age");
    List<List<String>> sortedData2 = sortByColumn(columnData, 2);
}
public static List<List<String>> sortByColumn(List<List<String>> list,
                                              String name) {
    // finding index of column by name
    int index = IntStream.range(0, list.get(0).size())
            .filter(i -> list.get(0).get(i).equals(name))
            .findFirst()
            .getAsInt();
    // sorting by index
    return sortByColumn(list, index);
}
public static List<List<String>> sortByColumn(List<List<String>> list,
                                              int index) {
    // preparing a new sorted list
    List<List<String>> sorted = new ArrayList<>(list.size());
    // header row
    sorted.add(list.get(0));
    // other rows, sorting by a specific column
    sorted.addAll(list.stream().skip(1)
            .sorted(Comparator.comparing(row -> row.get(index)))
            .collect(Collectors.toList()));
    return sorted;
}

排序数据1排序数据2

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

在这种情况下,使用2d数组而不是2d列表更有用,这样您就可以使用 Arrays.sort(T[],int,int,Comparator) 方法:

List<List<String>> columnData = List.of(
        List.of("Name", "Age", "Salary"),
        List.of("Lim", "20", "2000"),
        List.of("Tan", "20", "3000"),
        List.of("Mah", "19", "2500"),
        List.of("Roger", "10", "4000"));

String[][] arr = columnData.stream()
        .map(list -> list.toArray(String[]::new))
        .toArray(String[][]::new);

Arrays.sort(arr, 1, arr.length, Comparator.comparing(row -> row[1]));

原始列表排序数组

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

62o28rlo3#

你做的一切都是对的(除了变量名不应该全是大写的)。
在排序之前,只需删除第一个元素。然后排序,并将标题添加回列表:

List<String> header = columnData.get(0);
columnData.remove(0);
columnData.sort(getComparator("Age", header));
columnData.add(0, header);

如何将列号传递给比较器:

private Comparator<List<String>> getComparator(String column,
                                               List<String> header) {
    int index = header.indexOf(column);
    return new Comparator<List<String>>() {
        @Override
        public int compare(List<String> object1, List<String> object2) {
            return object1.get(index).compareTo(object2.get(index));
        }
    };
}
vshtjzan

vshtjzan4#

你可以用 List.subList(int,int) 方法获取此列表中在指定索引之间由此列表支持的部分,然后使用 Collections.sort(List,Comparator) 方法。此代码应适用于 Java 7 :

List<List<String>> columnData = Arrays.asList(
        Arrays.asList("Name", "Age", "Salary"),
        Arrays.asList("Lim", "20", "2000"),
        Arrays.asList("Tan", "20", "3000"),
        Arrays.asList("Mah", "19", "2500"),
        Arrays.asList("Roger", "10", "4000"));
Collections.sort(columnData.subList(1, columnData.size()),
        new Comparator<List<String>>() {
            @Override
            public int compare(List<String> o1, List<String> o2) {
                return o1.get(1).compareTo(o2.get(1));
            }
        });

排序前排序后

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

另请参见:
•基于值排序列表<map<string,object>>
•在java中,如何将矩阵逆时针旋转90度?

ugmeyewa

ugmeyewa5#

下面是如何按你的要求做。一旦定义了比较器,只需在 sublist 从列表1开始,跳过标题。因为它是原始列表的视图,所以它仍然对所需的项进行排序。
首先做一个字段Map,在哪个字段上排序。如果你想的话,可以不区分大小写。在这个例子中,案例很重要。

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。
原因是它允许混合类型存储在同一个对象中,并且仍然可以进行排序。如果你在一个 String number 它会分类的 lexcally 而不是 numerically . 这将是一个问题,除非您转换为整数(要看到这一点,请更改 4000400 按上述工资排序)。但是如果您想按名称排序,则需要一个不同的比较器,因为将非int转换为int会引发异常。这一切都可以在某种程度上得到缓解,但这并不像创建一个类那样简单。
只需将方法引用更改为所需的 getter 你可以把这些东西分类 List 在任何领域。如果没有getter,并且字段是public(不推荐),那么可以使用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

相关问题