首页 > Java > java教程 > 正文

Java中高效删除文本文件重复行:基于首字段的策略与实现

DDD
发布: 2025-12-03 19:34:55
原创
463人浏览过

java中高效删除文本文件重复行:基于首字段的策略与实现

本教程详细阐述了在Java中如何根据行的首个字段识别并删除文本文件中的重复行,并将处理后的数据存储到列表中。文章深入探讨了两种主要方法:一是利用Java Stream API的`Collectors.toMap`结合自定义合并函数直接处理字符串列表;二是引入自定义领域对象(如Company类)来封装数据,并通过对象ID进行去重,从而提升代码的可读性和维护性。教程包含详细的代码示例和实现解析。

在处理文本数据时,我们经常会遇到需要去除重复记录的场景。特别是在日志文件或数据导入导出中,如果重复的定义是基于行内某个特定字段(例如,行的第一个逗号分隔值),那么传统的List.stream().distinct()方法将无法满足需求,因为它会比较整行字符串的完全一致性。本文将介绍如何在Java中,针对以首字段作为重复判断依据的文本行,进行高效的去重操作,并将结果存储到ArrayList中。

理解问题:基于首字段的重复判断

假设我们有一个文本文件,内容如下:

123456,greenwitch street,near dominos store,Opp sandwitch company,Neyork,US,876890
123480,Postwitch street,near KFC store,Opp masala company,Newyork,US,876891
123456,Newyork street,near 100th avenue,King master company,Texas,US,10005
登录后复制

在这个例子中,第一行和第三行的起始数字“123456”是相同的,但行的其余部分不同。我们的目标是删除整个第三行,因为其首字段与第一行重复。

立即学习Java免费学习笔记(深入)”;

解决方案一:利用 Collectors.toMap 直接处理字符串

Java 8引入的Stream API为处理集合数据提供了强大而灵活的工具。Collectors.toMap()方法特别适用于根据某个键值进行聚合或去重。其核心思想是:将每行数据解析出一个作为键(Key)的唯一标识,并将整行数据作为值(Value)存储起来。当遇到重复的键时,通过一个合并函数(mergeFunction)来决定保留哪个值。

无界AI
无界AI

一站式AI创作、搜索、分享服务

无界AI 233
查看详情 无界AI

1. 核心原理

我们将行的第一个逗号分隔值作为键。如果遇到相同的键,我们选择保留第一次出现的值(即最早的记录)。

2. 代码实现

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class DuplicateRowRemover {

    public static void main(String[] args) {
        List<String> sourceList = List.of(
            "123456,greenwitch street,near dominos store,Opp sandwitch company,Neyork,US,876890",
            "123480,Postwitch street,near KFC store,Opp masala company,Newyork,US,876891",
            "123456,Newyork street,near 100th avenue,King master company,Texas,US,10005"
        );

        List<String> uniqueList = sourceList.stream()
            .collect(Collectors.toMap(
                str -> str.substring(0, str.indexOf(',')), // keyMapper: 提取第一个逗号前的子字符串作为键
                Function.identity(),                       // valueMapper: 整行字符串作为值
                (left, right) -> left                      // mergeFunction: 遇到重复键时,保留左边(即第一个遇到的)值
            ))
            .values()                                      // 获取Map中所有的值(即去重后的行)
            .stream()
            .toList();                                     // 转换为List

        System.out.println("去重后的列表 (字符串方式):");
        uniqueList.forEach(System.out::println);
    }
}
登录后复制

3. 代码解析

  • keyMapper (str -> str.substring(0, str.indexOf(','))): 这个函数负责从每行字符串中提取出作为唯一标识的键。它找到第一个逗号的位置,并截取从开头到该位置的子字符串。
  • valueMapper (Function.identity()): 这个函数指定了Map中存储的值。Function.identity()表示将当前流中的元素本身作为值。
  • mergeFunction ((left, right) -> left): 这是处理重复键的关键。当Collectors.toMap在处理流时遇到一个已经存在于Map中的键时,它会调用这个函数来决定保留哪个值。left代表Map中已有的值,right代表当前流中新遇到的值。-> left表示我们选择保留Map中已有的值,即第一个遇到的记录。如果选择-> right,则会保留最后一个遇到的记录。
  • .values().stream().toList(): 在完成收集后,Map中存储的键值对是唯一的。我们通过.values()获取所有去重后的行字符串集合,然后将其转换回List。

解决方案二:引入自定义领域对象(Domain Class)

直接操作字符串虽然简单,但当数据结构复杂、字段较多时,容易出错且代码可读性差。更专业的做法是定义一个领域对象(如Company类)来封装每行数据,并通过对象的ID属性进行去重。这不仅提升了代码的类型安全性和可读性,也为后续的数据操作提供了便利。

1. 定义领域对象

我们将创建一个Company类来表示文本文件中的每一条公司记录。为了简洁,这里使用Lombok的@Getter和@Builder注解。

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class Company {
    private long id;
    private String street;
    private String locationDescription;
    private String companyName;
    private String state;
    private String country;
    private String zipCode;

    // 静态方法,用于将字符串行解析为Company对象
    public static Company parse(String line) {
        String[] arr = line.split(",");
        if (arr.length < 7) { // 简单校验数据完整性
            throw new IllegalArgumentException("Invalid line format: " + line);
        }
        return Company.builder()
            .id(Long.parseLong(arr[0]))
            .street(arr[1]) // 根据数据结构补充street字段
            .locationDescription(arr[2])
            .companyName(arr[3])
            .state(arr[4])
            .country(arr[5])
            .zipCode(arr[6])
            .build();
    }

    @Override
    public String toString() { // 方便打印
        return id + "," + street + "," + locationDescription + "," + companyName + "," + state + "," + country + "," + zipCode;
    }
}
登录后复制

注意: 原始数据中包含street字段,为了保证数据完整性,Company.parse()方法中已补充该字段的解析。

2. 使用领域对象进行去重

有了Company类后,我们可以先将每行字符串映射成Company对象,然后再利用Collectors.toMap以Company对象的id作为键进行去重。

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class DuplicateCompanyRemover {

    public static void main(String[] args) {
        List<String> sourceList = List.of(
            "123456,greenwitch street,near dominos store,Opp sandwitch company,Neyork,US,876890",
            "123480,Postwitch street,near KFC store,Opp masala company,Newyork,US,876891",
            "123456,Newyork street,near 100th avenue,King master company,Texas,US,10005"
        );

        List<Company> uniqueCompanies = sourceList.stream()
            .map(Company::parse)                           // 将每行字符串解析为Company对象
            .collect(Collectors.toMap(
                Company::getId,                            // keyMapper: 使用Company对象的ID作为键
                Function.identity(),                       // valueMapper: Company对象本身作为值
                (left, right) -> left                      // mergeFunction: 遇到重复ID时,保留第一个Company对象
            ))
            .values()
            .stream()
            .toList();

        System.out.println("\n去重后的列表 (Company对象方式):");
登录后复制

以上就是Java中高效删除文本文件重复行:基于首字段的策略与实现的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号