使用 Java 流 API 解析具有交替数据行的逗号分隔文本文件

问题描述 投票:0回答:2

我有这个文件要处理,我正在尝试弄清楚如何将第二行读取为不同的对象。在行的末尾,最后一项是公交车的数量。第二行、第四行等应包含

idBus
noOfBus
,并用逗号分隔。

1,Harvard University,2
1,140,2,56
2,Massachusetts Institute of Technology,2
1,240,5,56
3,University of California Berkeley,3
1,112,2,56,3,28
4,Columbia University,4
1,84,2,84,3,84,7,28

基于这些课程

class University {
   public int idUniversity;
   public String nameOfUniversity;
   public int noOfBuses;
}
class Bus {
   public int idBus;
   public int noOfBus;
}

我想要一个函数来处理 CSV 文件中所有公交车和大学线路的列表。它必须使用流 API。我不知道是否可能或如何进行。

当然,可以基于类进行更改,但保留变量而不添加任何额外内容。

我认为最方便的事情是遍历文件并根据两个类(

University
Bus
)获取两个列表,最后将它们添加到第三个列表中,然后进行处理,但我不这样做不知道怎么办。

基于这个文件,我必须使用流 API 进行处理,例如“按 ID 对公交车进行排序”或“哪些大学有更多公交车?”或者“哪辆巴士去几所大学?”。

这就是我一直在努力做的事情。通常这就是我浏览 CSV 文件的方式。

private static List<University> readListOfUniversities() throws IOException {
    try (BufferedReader bufferedReader = new BufferedReader(new FileReader(PATH_UNIVERSITIES_TEXT_FILE))) {
        return bufferedReader.lines().map(line -> {
            String[] tokens = line.split(",");
            var idUniversity = Integer.parseInt(tokens[0]);
            var nameOfUniversity = tokens[1].trim();
            var noOfBuses = Integer.parseInt(tokens[2]);
            var university = new University(idUniversity, nameOfUniversity, noOfBuses);
            return university;
        }).collect(Collectors.toList());
    }
}

比如这个:

1,Harvard University,2
2,Massachusetts Institute of Technology,2
3,University of California Berkeley,3
4,Columbia University,4
java file java-stream
2个回答
0
投票

这就是我的做法(我对你的课程做了一些轻微的修改)

public class University {
    private int id;
    private String name;
    private List<Bus> busList;
    //let the constructor do the work
    public University(String [] data, List<Bus> busList) {
        id = Integer.parseInt(data[0]);
        name = data[1];
        this.busList = busList; 
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public List<Bus> getBusList() {
        return busList;
    }

    @Override
    public String toString() {
        return "University [id=" + id + ", name=" + name + ", busList=" + busList + "]";
    }
    
}

public class Bus {
    private int id;
    private int num;
    
    public Bus(int id, int num) {
        this.id = id;
        this.num = num;
    }
    
    public int getId() {
        return id;
    }

    public int getNum() {
        return num;
    }
    //Method to parse the data into usuable objects
    public static List<Bus> generateBusInfo(String [] data) {
        List<Bus> buses = new ArrayList<>();
        for (int i = 0; i < data.length-1; i+=2) {
            int id = Integer.parseInt(data[i]);
            int num = Integer.parseInt(data[i+1]);
            buses.add(new Bus(id, num));
        }
        return buses;
    }

    @Override
    public String toString() {
        return "Bus [id=" + id + ", num=" + num + "]";
    }
}


public static void main(String[] args) throws IOException {
    //This is just so I dont have to bother with creating a file.
    String input = "1,Harvard University,2\n" + 
            "1,140,2,56\n" + 
            "2,Massachusetts Institute of Technology,2\n" + 
            "1,240,5,56\n" + 
            "3,University of California Berkeley,3\n" + 
            "1,112,2,56,3,28\n" + 
            "4,Columbia University,4\n" + 
            "1,84,2,84,3,84,7,28\n";
    List<University> universities = new ArrayList<>();
    //replace StringReader with a FileReader to the path of your file.
    try(BufferedReader reader = new BufferedReader(new StringReader(input))) {
        //read the first line
        String line = reader.readLine();
        while (line != null) { //keep reading until you're done
            String [] uniData = line.split(","); //convert string into an array
            line = reader.readLine(); //read the next line
            if (line != null) {
                String [] busData = line.split(","); //convert
                List<Bus> busList = Bus.generateBusInfo(busData); //make busses
                universities.add(new University(uniData, busList)); //create university and add it to the list
                line = reader.readLine(); //read the next line
            }
        }
    }
    
    //output the list
    for (University uni : universities) {
        System.out.println(uni);
    }
}

您还可以将大学和巴士读入

Map
以方便访问。


0
投票

给定大学及其公交车的数据在数据中连续排列。 一次传输两条线路的数据将允许获取大学及其相关的总线数据。

JEP 461:流收集器Java 22 预览语言功能可用于实现此目标,因为它添加了对将流分区为给定大小的列表的内置支持。 在这种情况下,线路的 2 元素列表将返回每所大学及其公交车详细信息。

public record UniversityAndBuses(University university, List<Bus> buses) {} private static List<UniversityAndBuses> readListOfUniversities() throws IOException { try (BufferedReader bufferedReader = new BufferedReader(new FileReader(PATH_UNIVERSITIES_TEXT_FILE))) { return bufferedReader.lines().gather(Gatherers.windowFixed(2)).map(lines -> { String[] universityTokens = lines.get(0).split(","); University university = new University( Integer.parseInt(universityTokens[0]), universityTokens[1], Integer.parseInt(universityTokens[2])); List<Bus> buses = Arrays.stream(lines.get(1).split(",")) .gather(Gatherers.windowFixed(2)) .map(idAndNo -> new Bus( Integer.parseInt(idAndNo.get(0)), Integer.parseInt(idAndNo.get(1)) )) .collect(Collectors.toList()); return new UniversityAndBuses(university, buses); }).toList(); } }
这使用新的 

Stream.gather

 方法和新的内置 Gatherers.windowFixed
 收集器将初始 
Stream<T>
 转换为 
Stream<List<T>>
,列表大小为 2。它读取每个列表的第一个元素到一个 
University
 对象,每个列表的第二个元素到一个 
List<Bus>
。  它将这些元素组合成一个包含这两个值的 
UniversityAndBuses
 记录。  最终,该流转换为 
List<UniversityAndBuses>

此解决方案中也使用了相同的技术,将每行总线数据解析为

List<Bus>

,因为总线数据行是交替总线 ID/总线编号对的逗号分隔列表。

Java文档

Gatherer


将输入元素流转换为输出元素流的中间操作,可以选择在到达上游末尾时应用最终操作。 […]

[…]

聚集操作的例子有很多,包括但不限于:将元素分组(窗口函数);对连续相似的元素进行去重;增量累加功能(前缀扫描);增量重新排序功能等。类

Gatherers

提供了常见收集操作的实现。

Stream.gather


返回一个流,其中包含将给定收集器应用于该流的元素的结果。

Gatherers.windowFixed


返回一个收集器,它将元素收集到固定大小的窗口中——遇到有序的元素组。如果流为空,则不会生成任何窗口。最后一个窗口包含的元素可能少于提供的窗口大小。

示例:

// will contain: [[1, 2, 3], [4, 5, 6], [7, 8]] List<List<Integer>> windows = Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowFixed(3)).toList();

    
© www.soinside.com 2019 - 2024. All rights reserved.