如何从CSV文件提取特定数据?基于ArrayList的功能实现求助
先修正你的CSV读取逻辑
首先得说,你当前用Scanner.next()读取CSV的方式有问题——这个方法会把所有空格分隔的内容拆成ArrayList的单个元素,完全破坏了CSV按行、按逗号分隔的结构(比如地址里的空格会把一个字段拆成好几个)。这会导致后续的所有操作都很难做,所以先把读取逻辑改对:
步骤1:创建房产数据类
先定义一个Property类来封装每条房产记录的字段,这样操作起来更清晰:
public class Property { private int id; private String propertyAddress; private String firstName; private String lastName; private String email; private boolean isOwner; // 对应Owner字段,空值可处理为false private double price; private LocalDate date; private boolean isSold; // 对应sold字段 // 构造方法 public Property(int id, String propertyAddress, String firstName, String lastName, String email, boolean isOwner, double price, LocalDate date, boolean isSold) { this.id = id; this.propertyAddress = propertyAddress; this.firstName = firstName; this.lastName = lastName; this.email = email; this.isOwner = isOwner; this.price = price; this.date = date; this.isSold = isSold; } // 省略getter方法,比如getId(), getPrice(), getDate(), isSold()等,需要自行补充 }
步骤2:正确读取CSV到对象列表
改用nextLine()读取整行,再按逗号分割字段,然后把字段转换成Property对象存入列表:
Path filepath = Paths.get("./data.csv"); List<Property> propertyList = new ArrayList<>(); try (Scanner scanner = new Scanner(filepath)) { // 跳过表头行 if (scanner.hasNextLine()) { scanner.nextLine(); } while (scanner.hasNextLine()) { String line = scanner.nextLine(); // 按逗号分割字段(如果字段里有带逗号的情况,建议用专门的CSV解析库比如OpenCSV) String[] fields = line.split(","); // 解析每个字段,注意处理空值和字段位置(对应你提供的CSV结构) int id = Integer.parseInt(fields[0].trim()); // 拼接地址字段(比如把拆分的地址部分合并) String propertyAddress = fields[1].trim() + " " + fields[2].trim(); String firstName = fields[3].trim(); String lastName = fields[4].trim(); String email = fields[5].trim(); boolean isOwner = !fields[6].trim().isEmpty(); double price = Double.parseDouble(fields[8].trim()); // 对应Price字段位置 LocalDate date = LocalDate.parse(fields[9].trim()); // 假设日期格式符合ISO标准,否则需要DateTimeFormatter boolean isSold = !fields[10].trim().isEmpty(); Property property = new Property(id, propertyAddress, firstName, lastName, email, isOwner, price, date, isSold); propertyList.add(property); } } catch (IOException e) { e.printStackTrace(); }
小提示:如果你的CSV字段里有带逗号的内容(比如地址里的逗号),手动用
split(",")会出错,建议用成熟的CSV解析库,比如OpenCSV,它能处理带引号的特殊字段。
实现你需要的三个功能
现在有了结构化的Property列表,三个功能就很容易实现了:
1. 通过ID获取房产记录
方法1:遍历列表(适合数据量小的场景)
public Property getPropertyById(List<Property> propertyList, int targetId) { for (Property property : propertyList) { if (property.getId() == targetId) { return property; } } return null; // 没找到返回null }
方法2:用HashMap做映射(查询更快,适合数据量大的场景)
先把列表转成HashMap做缓存:
Map<Integer, Property> propertyMap = new HashMap<>(); for (Property property : propertyList) { propertyMap.put(property.getId(), property); }
之后查询直接通过Key获取,速度更快:
Property targetProperty = propertyMap.get(targetId);
2. 获取n个最高价房产的列表
对列表按价格降序排序,然后取前n个即可:
public List<Property> getTopNExpensiveProperties(List<Property> propertyList, int n) { // 复制原列表避免修改源数据,按价格降序排序 List<Property> sortedList = new ArrayList<>(propertyList); sortedList.sort((p1, p2) -> Double.compare(p2.getPrice(), p1.getPrice())); // 处理n大于列表长度的情况,避免越界 int takeCount = Math.min(n, sortedList.size()); return sortedList.subList(0, takeCount); }
3. 统计月度总销售额
提取每个已售出房产的月份,然后累加对应月份的销售额:
public Map<Month, Double> getMonthlySales(List<Property> propertyList) { Map<Month, Double> monthlySales = new EnumMap<>(Month.class); for (Property property : propertyList) { if (property.isSold()) { // 只统计已售出的房产 Month month = property.getDate().getMonth(); double currentSales = monthlySales.getOrDefault(month, 0.0); monthlySales.put(month, currentSales + property.getPrice()); } } return monthlySales; }
如果需要按「年份+月份」统计(比如2023年1月、2023年2月),可以把Map的Key换成
YearMonth:Map<YearMonth, Double> monthlySales = new HashMap<>(); // 内部替换为: YearMonth yearMonth = YearMonth.from(property.getDate());
内容的提问来源于stack exchange,提问作者Kabira S
相关产品推荐
相关产品推荐

