新闻中心
J*a中基于首字段删除文本文件重复行并生成唯一记录列表

本教程详细介绍了如何在j*a中处理文本文件,根据每行记录的首个字段(例如id)删除重复行,并将去重后的数据存储到列表中。文章提供了两种主要方法:一是利用j*a stream api的`collectors.tomap`结合自定义合并函数直接处理字符串列表;二是建议通过引入领域对象(如`company`类)来封装数据,提高代码的可读性和可维护性,并演示了如何解析字符串到对象并进行去重操作。
在数据处理场景中,我们经常需要从文本文件中读取数据,并根据特定规则删除重复记录。一个常见的需求是,当每行记录由多个字段组成,且我们只关注某个特定字段(例如行首的ID)是否重复时,需要删除整行重复的记录。本文将介绍两种在J*a中实现这一目标的高效方法。
方法一:使用 Collectors.toMap 直接处理字符串列表
J*a 8引入的Stream API为集合操作提供了强大且简洁的工具。对于根据某个键去重并保留第一条记录的场景,Collectors.toMap 是一个非常合适的选择。
Collectors.toMap 方法通常有三个参数:
- keyMapper: 用于从流中的元素提取键的函数。
- valueMapper: 用于从流中的元素提取值的函数。
- mergeFunction: 当遇到重复键时,用于解决冲突的函数。
在这个场景中,我们需要将每行的第一个逗号分隔的值作为键,整行字符串作为值。当键重复时,我们选择保留第一个遇到的值。
import j*a.util.List;
import j*a.util.function.Function;
import j*a.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 *enue,King master company,Texas,US,10005"
);
List<String> uniqueList = sourceList.stream()
.collect(Collectors.toMap(
str -> str.substring(0, str.indexOf(',')), // keyMapper: 提取第一个逗号前的子字符串作为键
Function.identity(), // valueMapper: 保留原始字符串作为值
(existing, replacement) -> existing // mergeFunction: 遇到重复键时,保留已存在的(即第一个遇到的)
))
.values() // 获取Map中所有的值(即去重后的字符串)
.stream()
.toList(); // 将值转换为List
System.out.println("去重后的字符串列表:");
uniqueList.forEach(System.out::println);
}
}代码解析:
- str -> str.substring(0, str.indexOf(',')): 这个Lambda表达式作为 keyMapper,它从每行字符串中提取出第一个逗号之前的部分作为唯一标识符(键)。
- Function.identity(): 作为 valueMapper,表示我们希望Map的值就是原始的字符串本身。
- (existing, replacement) -> existing: 这是 mergeFunction,它在 Collectors.toMap 遇到相同的键时被调用。existing 是Map中已经存在的与该键关联的值,replacement 是当前尝试插入的新值。我们选择返回 existing,这意味着我们保留了第一个遇到的具有该键的记录,而丢弃了后续的重复记录。
- .values().stream().toList(): 在去重完成后,我们从生成的Map中取出所有的值(这些值就是去重后的原始字符串),并将其收集成一个新的 List。
方法二:引入领域对象提升代码可维护性
直接操作字符串虽然简洁,但当数据结构复杂或需要对字段进行更多操作时,容易出错且可读性差。更健壮的方法是定义一个领域(Domain)对象来封装每行数据,然后对这些对象进行去重操作。这不仅提高了代码的类型安全性和可读性,也为后续的数据处理提供了便利。
首先,我们定义一个 Company 类来表示文本文件中的每条记录:
import lombok.Builder;
import lombok.Getter; // 假设使用Lombok简化代码,如果不用,需要手动生成getter方法
@Builder
@Getter
public class Company {
private long id;
private String street;
private String locationDescription;
private String companyName;
private String state;
privat
e 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;
}
}说明:
神笔马良
神笔马良 - AI让剧本一键成片。
320
查看详情
- @Builder 和 @Getter 是Lombok注解,它们会自动生成构造器和Getter方法,减少样板代码。如果项目中没有Lombok,需要手动实现这些方法。
- parse(String line) 静态方法负责将一行字符串解析成 Company 对象。它通过逗号分割字符串,并将各个部分赋值给对应的字段。这里增加了对 street 字段的解析,使其与原始数据格式保持一致。
- toString() 方法重写是为了方便打印 Company 对象时能看到其内容,或者在需要将对象转回字符串时使用。
接下来,我们使用这个 Company 类来处理数据并去重:
import j*a.util.List;
import j*a.util.function.Function;
import j*a.util.stream.Collectors;
// 假设Company类已定义如上
public class CompanyDuplicateRemover {
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 *enue,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对象本身作为值
(existing, replacement) -> existing // mergeFunction: 遇到重复ID时,保留第一个Company对象
))
.values() // 获取Map中所有的Company对象
.stream()
.toList(); // 将对象转换为List
System.out.println("去重后的Company对象列表:");
uniqueCompanies.forEach(company -> System.out.println(company.toString())); // 打印Company对象
}
}代码解析:
- .map(Company::parse): 这是关键一步,它将 String 类型的流转换为 Company 对象的流。
- Company::getId: 作为 keyMapper,我们现在可以直接通过 Company 对象的 getId() 方法来获取作为键的ID,这比字符串操作更安全、更直观。
- Function.identity(): 作为 valueMapper,Map中存储的是 Company 对象本身。
- mergeFunction 的逻辑与方法一相同,只是现在处理的是 Company 对象。
注意事项与最佳实践
-
文件I/O处理: 上述示例假定数据已在 List
中。在实际应用中,您需要从文本文件读取数据。可以使用 j*a.nio.file.Files.lines() 方法来高效地逐行读取文件内容,并直接将其作为Stream的源: import j*a.io.IOException; import j*a.nio.file.Files; import j*a.nio.file.Paths; import j*a.util.List; import j*a.util.stream.Collectors; // ... (Company 类和 Collectors.toMap 逻辑) try (var lines = Files.lines(Paths.get("your_text_file.txt"))) { List<Company> uniqueCompanies = lines .map(Company::parse) .collect(Collectors.toMap( Company::getId, Function.identity(), (existing, replacement) -> existing )) .values() .stream() .toList(); // 处理 uniqueCompanies } catch (IOException e) { System.err.println("Error reading file: " + e.getMessage()); } catch (IllegalArgumentException e) { System.err.println("Error parsing line: " + e.getMessage()); } -
错误处理:
- 在 Company.parse() 方法中,Long.parseLong() 可能会抛出 NumberFormatException,如果ID不是有效的数字。
- line.split(",") 后的数组长度可能不足,导致 ArrayIndexOutOfBoundsException。
- str.indexOf(',') 返回 -1 时,substring() 会抛出 StringIndexOutOfBoundsException。 在生产代码中,应捕获这些异常,或在解析前进行严格的数据校验,确保程序的健壮性。
-
性能与内存:
- 对于小到中等大小的文件(例如几GB以内),上述Stream和Map的方法通常效率很高。
- 对于非常大的文件(例如几十GB甚至更大),将所有数据一次性加载到内存中可能会导致 OutOfMemoryError。在这种情况下,可以考虑:
- 分批处理(chunking):每次读取固定数量的行进行处理。
- 使用外部排序或数据库:将数据导入数据库,利用数据库的唯一索引或去重功能。
- Bloom Filter:对于判断是否存在重复键的场景,可以在内存有限的情况下提供概率性去重。
-
选择方法:
- 如果数据结构简单,且去重后不需要进一步的字段操作,方法一(直接操作字符串)更简洁。
- 如果数据结构复杂,或者去重后还需要对各个字段进行操作、校验、转换等,强烈建议使用方法二(引入领域对象)。这会大大提高代码的可读性、可维护性和扩展性。
总结
本文详细介绍了在J*a中根据文本文件行的首个字段删除重复记录的两种有效策略。通过利用J*a Stream API的 Collectors.toMap,我们可以灵活地定义去重规则。对于简单场景,直接操作字符串是快速有效的方案;而对于复杂或需要高可维护性的项目,引入领域对象并结合Stream API进行处理,无疑是更专业和健壮的选择。在实际应用中,务必结合文件I/O、错误处理和性能考量,选择最适合您需求的实现方式。
以上就是J*a中基于首字段删除文本文件重复行并生成唯一记录列表的详细内容,更多请关注其它相关文章!
# 数据处理
# 联邦快递网站建设银行
# 爱站seo vip账号
# 常州关键词排名制造厂
# 卢松松seo工具
# 三人行seo
# 新乡网站推广优化多少钱
# 商城网站建设优化企业
# sem与seo哪个难
# 人工计划软件seo
# 桥东区营销网络推广
# 首个
# 详细介绍
# java
# 并将
# 这是
# 的是
# 两种
# 数据结构
# 文本文件
# 第一个
# 字符串解析
# stream
# ai
# 工具
# app
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
sublime怎么预览Markdown渲染效果_Markdown Preview插件 for sublime教程
yy漫画网页版官方入口_yy漫画官网登录页面链接
C++如何实现一个装饰器模式_C++设计模式之动态地给对象添加额外职责
照顾宝贝2小游戏点击立即在线玩
漫蛙漫画官方主页入口 漫蛙MANWA网页直达访问链接
《明末:渊虚之羽》设计师谈设计角色:那会刚毕业 充满激情
Win11如何开启讲述人功能 Win11屏幕阅读器(讲述人)开启与关闭【教程】
163邮箱登录密码 163邮箱忘记密码找回
wps文字怎么插入目录并自动更新_wps文字如何插入目录并自动更新方法
html两个JS只运行一个怎么办_让双JS在html中都运行方法【技巧】
PyTorch模型训练效果不佳?深入剖析常见错误与调试技巧
b站赚钱渠道_b站收益来源
如何设置Windows Defender的定时扫描_计划任务实现自动杀毒【安全】
Python类型检查:优化关联可选属性的Mypy推断策略
千牛数据看板网页版_千牛数据看板网页版访问方法
Shopware订单对象中获取产品自定义字段的正确方法
Adobe PDF表单中利用J*aScript解析与格式化日期组件的教程
C++如何比较两个字符串_C++ string compare函数与操作符对比
poki免费入口快捷访问 poki人气小游戏直接玩站点
蛙漫安全无毒 官方认证的绿色入口
Go RPC HTTP服务正确实现与常见陷阱解析
极速漫画官方主页网址 极速漫画漫画在线浏览官网链接
css链接悬停下划线样式如何自定义_使用::after结合content和transition
Centos/Linux 系统下安装 composer 的完整步骤
CSS Grid如何控制元素对齐_align-items与justify-items组合使用
Pandas DataFrame:高效添加条件计算列
Go语言中动态执行代码字符串的策略与实践
顺丰快件物流信息 官方网站查询入口
漫蛙官网正版漫画入口 漫蛙2官方网页登录地址
Win11如何使用Windows Sandbox Win11沙盒功能开启与使用教程【详解】
Golang如何优化CPU绑定任务分配策略_Golang CPU任务分配优化实践
谷歌邮箱注册显示错误Gmail服务器异常与延迟处理
win11开机启动修复循环怎么办 Win11无法进入系统高级启动解决方法【修复】
b站怎么看视频的弹幕数量_b站弹幕数量查看方法
AI抖音网页版免费视频入口 AI抖音网页端最新视频实时观看
uc手机浏览器网页版入口 uc浏览器手机版便捷登录首页
Safari自带网页翻译功能怎么用 无需插件轻松看懂外文网站【方法】
J*aScript数组对象转换:按指定键分组与值收集
PySpark中高效提取字符串右侧可变长度数字:使用regexp_extract
Excel中VLOOKUP的第四个参数是干什么用的_Excel VLOOKUP第四参数作用解析
Golang如何通过reflect获取匿名字段方法_Golang reflect匿名字段方法访问技巧
移动端XML文件怎么转换成Excel 手机和平板上的解决方案
解决J*aScript中重复选择项的确认对话框显示问题
Yandex浏览器官方网页版入口 Yandex浏览器最新版官网
Golang如何实现Web文件静态资源服务器_Golang静态资源服务器开发与实践
在Go语言中利用后缀数组处理多字符串:实现高效文本匹配与自动补全
c++中的std::launder有什么实际用途_c++对象生命周期与指针优化
漫蛙漫画官方首页 漫蛙2漫画在线阅读入口
MongoDB Aggregation:在嵌套对象数组中精确匹配ObjectId
J*a里如何使用forEach遍历Map_Map遍历方法说明


2025-12-03
浏览次数:次
返回列表
e 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;
}
}