根据字符串分组

本文介绍了一种使用Java List对特定格式的字符串进行分组的方法,并对每组执行相应操作的过程。通过对字符串后缀的判断实现自动分组,进而可以针对不同组执行不同的批量操作。

今天要做一个根据字符串分组,然后集体执行一个操作,想了一上午,动态创建数组什么的,最后还是用了list。

List allList=new ArrayList();
  String m1="a123_x1";
  String m2="a124_x1";
  String m3="a125_x2";
  String m4="a126_x2";
  String m5="a127_x3";
  String m6="a128_x3";
  String m7="a129_x3";
  allList.add(m1);
  allList.add(m2);
  allList.add(m3);
  allList.add(m4);
  allList.add(m5);
  allList.add(m6);
  allList.add(m7);
  String sufxList="";
  
  for(int i=0;i<allList.size();i++){
   String picId =(String) allList.get(i);
   String sufx = picId.substring(picId.lastIndexOf("_")+1);
   String id = picId.substring(0,picId.lastIndexOf("_"));
   String aaj="";
   
   if(sufxList.indexOf(sufx)==-1){
    sufxList=sufxList +"&" +sufx;    //如果没有重复的后缀,也就是第一次出现,则把后缀加入进来。
   }
   System.out.println(sufx + "-------------"+id);
  }
  System.out.println("sufxList.................."+ sufxList);
  String[] aa=sufxList.split("&");
  //System.out.println("aa.length============"+ (aa.length));
//  if(aa.length==4){
//   System.out.println("aa[]........"+ aa[3]);
//  } 
  for(int j=1;j<aa.length;j++){
   List<String> list=new ArrayList();
   //System.out.println("aa===="+ aa[j]);
   //aaj=aa[j];
   System.out.println("当查询含有“"+aa[j]+ "“时");
    for(int n=0;n< 7;n++){
     String memb=(String)allList.get(n);
     //System.out.println("aaj------------"+aaj);
     if(memb.indexOf(aa[j])!=-1){    //说明里面有X1/X2/x3,所以放入X1组里去
      list.add(memb);      
      System.out.println("list的长度是。。。。。。。。。。。。"+list.size());
     }
     
    }
    for(int r=0;r<list.size();r++){
     System.out.println("list每个元素。。。。。。。。"+ list.get(r));
    }
   }

 

执行结果为:

x1-------------a123
x1-------------a124
x2-------------a125
x2-------------a126
x3-------------a127
x3-------------a128
x3-------------a129
sufxList..................&x1&x2&x3
当查询含有“x1“时
list的长度是。。。。。。。。。。。。1
list的长度是。。。。。。。。。。。。2
list每个元素。。。。。。。。a123_x1
list每个元素。。。。。。。。a124_x1
当查询含有“x2“时
list的长度是。。。。。。。。。。。。1
list的长度是。。。。。。。。。。。。2
list每个元素。。。。。。。。a125_x2
list每个元素。。。。。。。。a126_x2
当查询含有“x3“时
list的长度是。。。。。。。。。。。。1
list的长度是。。。。。。。。。。。。2
list的长度是。。。。。。。。。。。。3
list每个元素。。。。。。。。a127_x3
list每个元素。。。。。。。。a128_x3
list每个元素。。。。。。。。a129_x3

 

这样就可以对每一组进行操作了。

<think>嗯,用户现在的问题是想通过JSON字符串比较来实现DTO对象的分组,而且不希望直接修改复杂的DTO属性。他们提到的方法是将DTO转为JSON,删除特定字段(比如name),然后转为有序字符串,再比较字符串来进行分组。我需要仔细分析这个需求,并参考之前提供的解决方案和站内引用,给出一个可行的回答。 首先,用户之前的问题是关于如何在Java中不修改DTO的情况下进行动态分组,我给出的方案是使用反射机制提取属性值。现在用户想换一种方式,用JSON处理来实现分组,可能因为反射在某些情况下性能不够理想,或者他们更熟悉JSON操作。 用户提到的三个引用中,引用1提到了使用fastjson的toJSONStringWithDateFormat方法处理日期格式,引用2是关于将对象转为JSON字符串,引用3是使用GsonFormat插件生成实体类。这些引用可能对解决当前问题有帮助,比如处理JSON转换时的格式问题,或者生成中间结构。 接下来,我需要考虑如何将DTO转为JSON后删除特定字段。这可能需要使用JSON库的序列化配置,比如fastjson或Jackson,在转换时忽略某些字段。例如,fastjson的SerializerFeature可以配置排除某些字段,或者在转换过程中动态过滤字段。 然后,将处理后的JSON字符串排序,确保相同结构的对象生成的字符串一致,以便比较。这涉及到对JSON对象进行排序,可能需要使用有序的Map,比如LinkedHashMap,或者在序列化时保持键的顺序。 用户的需求是避免修改DTO,因此解决方案必须完全基于外部处理,不涉及DTO本身的注解或结构修改。这可能涉及到自定义序列化器,或者在转换过程中动态修改JSON结构。 另外,需要考虑性能问题。反射方案已经有性能损耗,而JSON处理可能更慢,尤其是处理大量数据时。不过,用户可能更看重实现的简便性和可维护性,所以需要权衡。 接下来,需要设计具体的实现步骤。首先,将对象转为JSON字符串,过滤掉不需要的字段(如name)。这可以通过在序列化时配置排除字段,或者在转换为JSON对象后手动移除特定键。然后,将JSON对象按键排序,生成有序的字符串,最后用这个字符串作为分组的关键字。 在代码实现上,可能需要用到fastjson的JSONObject或Jackson的ObjectMapper,结合自定义的过滤逻辑。例如,使用fastjson的JSON.parseObject将对象转为JSONObject,然后remove掉name字段,再对键进行排序,生成字符串。 同时,要确保不同字段顺序的JSON对象在排序后生成相同的字符串,这样它们才能被分到同一组。例如,使用TreeMap来存储键值对,保证键的顺序一致。 还需要考虑如何处理嵌套对象和数组的情况,确保所有层级的字段都被正确过滤和排序。可能需要递归处理JSON结构中的每一个对象和数组元素。 另外,引用中提到的fastjson的SerializerFeature.WriteDateUseDateFormat可以用来处理日期格式,确保日期字段在字符串中的一致性,避免因格式不同导致分组错误。 最后,需要评估这种方法的优缺点,比如灵活性高但可能有性能问题,适合中小规模数据,或者需要缓存JSON字符串以提高性能。 总结一下,解决方案的大致步骤是:序列化DTO为JSON,过滤特定字段,排序JSON键,生成有序字符串,使用该字符串作为分组键。具体实现需要选择合适的JSON库,处理字段过滤和排序,并确保效率和正确性。</think>基于JSON字符串比较实现DTO分组是一种灵活的非侵入式方案,特别适合处理不可修改的复杂DTO。以下是具体实现步骤和技术要点: ### 一、实现方案设计 #### 1. 核心流程 $$流程图$$ ```mermaid graph TD A[原始DTO对象] --> B[转换为JSON对象] B --> C[删除指定字段] C --> D[有序JSON字符串] D --> E[作为分组Key] ``` #### 2. 技术选型对比 | 方案 | 优点 | 缺点 | |------|------|------| | 反射方案 | 直接操作内存对象 | 需处理嵌套结构 | | JSON方案 | 天然处理复杂结构 | 序列化/反序列化开销 | ### 二、完整代码实现 ```java import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; import java.util.*; import java.util.stream.Collectors; public class JsonGroupingService { // 需要排除的字段集合 private static final Set<String> EXCLUDE_FIELDS = new HashSet<>(Arrays.asList("name")); public static Map<String, Long> groupByJsonKey(List<?> dtos) { return dtos.stream().collect( Collectors.groupingBy( dto -> generateOrderedKey(dto, EXCLUDE_FIELDS), Collectors.counting() ) ); } private static String generateOrderedKey(Object obj, Set<String> excludeFields) { // 转换为JSON对象并过滤字段 JSONObject jsonObj = (JSONObject) JSON.toJSON(obj); excludeFields.forEach(jsonObj::remove); // 生成有序字符串 return JSON.toJSONString( jsonObj, SerializerFeature.SortField, // 字段排序 SerializerFeature.WriteDateUseDateFormat // 统一日期格式[^1] ); } } ``` ### 三、关键实现细节 #### 1. 字段过滤策略 ```java // 动态过滤扩展:支持正则表达式匹配 private static void filterFields(JSONObject json, Pattern excludePattern) { json.entrySet().removeIf(entry -> excludePattern.matcher(entry.getKey()).matches() ); } ``` #### 2. 有序字符串生成 使用`SerializerFeature.SortField`确保字段按字母顺序排列: $$JSON排序示例$$ 原始对象:`{"b":2,"a":1,"c":3}` 排序结果:`{"a":1,"b":2,"c":3}` #### 3. 类型安全处理 ```java // 处理泛型对象 public static <T> Map<String, Long> genericGroupBy(List<T> dtos) { return dtos.stream().collect( Collectors.groupingBy( dto -> generateOrderedKey(dto, EXCLUDE_FIELDS), Collectors.counting() ) ); } ``` ### 四、性能优化建议 1. **缓存JSON字符串**:使用WeakHashMap缓存对象哈希值与JSON字符串的映射 2. **并行处理**:对大数据集使用parallelStream() 3. **选择性序列化**:通过@JSONField(serialize=false)注解跳过不需要的字段[^1] 4. **使用更高效的库**:Jackson的ObjectMapper性能优于Fastjson ### 五、扩展应用场景 1. **数据版本比对**:生成标准化数据指纹 2. **缓存键生成**:创建结构化缓存键 3. **日志脱敏处理**:自动过滤敏感字段 ### 六、方案对比 | 指标 | 反射方案 | JSON方案 | |------|---------|----------| | 可读性 | 需要理解反射机制 | 直观可见数据结构 | | 性能 | 反射调用开销 | 序列化开销 | | 嵌套处理 | 需要递归处理 | 自动展开嵌套结构 | | 类型安全 | 强类型检查 | 弱类型校验 | ### 七、异常处理策略 1. **循环引用检测**: ```java SerializerFeature.DisableCircularReferenceDetect ``` 2. **自定义序列化器**:处理特殊类型(如LocalDateTime) 3. **空值统一处理**: ```java jsonObj.putIfAbsent(field, "NULL_PLACEHOLDER"); ``` ### 八、应用示例 ```java // 测试DTO class User { private String name; private String department; private LocalDateTime createTime; // getters/setters } // 使用示例 List<User> users = Arrays.asList( new User("张三", "技术部", LocalDateTime.now()), new User("李四", "市场部", LocalDateTime.now()), new User("王五", "技术部", LocalDateTime.now()) ); Map<String, Long> result = JsonGroupingService.groupByJsonKey(users); /* 输出: {"createTime":"2023-07-20 14:30","department":"技术部"} -> 2 {"createTime":"2023-07-20 14:30","department":"市场部"} -> 1 */ ``` ### 九、相关技术延伸 1. **JSON Schema验证**:确保字段一致性 2. **JSON Patch**:实现差异比对 3. **JSON Path**:支持复杂查询 --相关问题--: 1. 如何优化大规模数据集的JSON序列化性能? 2. 如何处理JSON方案中的循环引用问题? 3. 不同JSON库在字段排序处理上有何差异? 4. 如何实现动态配置排除字段而非硬编码? [^1]: Fastjson的日期格式化特性可确保时间字段的一致性 [^2]: 使用字符串比较时需要统一序列化配置 [^3]: 复杂嵌套结构需要递归处理字段过滤
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值