Java 在运行时创建用于排序的复合比较器

Java 在运行时创建用于排序的复合比较器,java,json,spring-boot,Java,Json,Spring Boot,我的样本请求 { "requestModel":{ "CUSTID": "100" }, "returnParameters":[ { "name":"NETWORK/NETID", "datatype":"String", "order":"asc", "sequence":1 }, { "name":"INFODATA/NAME", "datatype":"String",

我的样本请求

 {
  "requestModel":{
      "CUSTID": "100"
     },
  "returnParameters":[
    {
     "name":"NETWORK/NETID",
     "datatype":"String",
     "order":"asc",
     "sequence":1
    },
    {
     "name":"INFODATA/NAME",
     "datatype":"String",
     "order":"asc",
     "sequence":1
    },
    {
     "name":"SOURCE/SYSTEM",
     "datatype":"int",
     "order":"asc",
     "sequence":2
    },
   ]
 }
样本响应

Map<String,Object> documentList = new HashMap<String,Object>();
JSONObject jsonObject= new JSONObject(response.getContent());
下面是我动态生成的json响应映射格式[响应参数每次都会根据请求参数而不同]

"responseModel":{
  "documents": [
{
 "NETWORK":[
    {"NETID":"1234"},
    {"ACT":"300"}
   ],
   "SOURCE": {
      "SYSTEM":"50"
     },
   "INFODATA":{
     "NAME":"PHIL"
     }
 },
 {
  "NETWORK":[
    {"NETID":"1234"},
    {"ACT":"300"}
   ],
   "SOURCE": {
      "SYSTEM":"100"
     },
   "INFODATA":{
     "NAME":"PHIL"
     }
  }
 ]
}
问题陈述

 {
  "requestModel":{
      "CUSTID": "100"
     },
  "returnParameters":[
    {
     "name":"NETWORK/NETID",
     "datatype":"String",
     "order":"asc",
     "sequence":1
    },
    {
     "name":"INFODATA/NAME",
     "datatype":"String",
     "order":"asc",
     "sequence":1
    },
    {
     "name":"SOURCE/SYSTEM",
     "datatype":"int",
     "order":"asc",
     "sequence":2
    },
   ]
 }
我需要根据请求中的“returnParameters”进行多级排序,这是动态的。。。 “order”表示升序(或降序),sequence表示排序的优先级,如(sql查询中的group by)

代码

Map<String,Object> documentList = new HashMap<String,Object>();
JSONObject jsonObject= new JSONObject(response.getContent());
有人能帮我在运行时创建复合比较器进行排序吗


注意:-无法创建Java Pojo,因为响应是动态的

我的建议:了解:

  • Comparator.comparating
    ,允许您通过指定密钥提取程序来构建比较器
  • Comparator.thanparcing
    ,它允许您链接多个比较器。只有当前辈说对象相等时,才调用链中后面的比较器

如果您需要教程:

我的建议:了解:

  • Comparator.comparating
    ,允许您通过指定密钥提取程序来构建比较器
  • Comparator.thanparcing
    ,它允许您链接多个比较器。只有当前辈说对象相等时,才调用链中后面的比较器

如果需要教程:

在注释中的附加问题和说明中的附加信息后编辑


要获得解决方案,您需要执行以下几个步骤:

  • 您希望根据请求中属性
    sequence
    的值动态排序。因此,您需要解析那些
    returnParameters
    的名称,并将它们按顺序排列。下面我将它们映射到一个列表中,其中每个字符串[]都有
    名称
    顺序
    (asc/desc)。将使用
    序列的值对列表进行排序

    List<String[]> sortParams = params.stream() // params is a List<JSONObject>
            .filter(json -> json.containsKey("sequence")) // filter those that have "sequence" attribute
            .sorted( sequence ) // sorting using Comparator called sequence
            .map(jsonObj -> new String[]{jsonObj.get("name").toString(), jsonObj.get("order").toString()} )
            .collect(Collectors.toList());
    
    因此,对于您的示例,排序图看起来像:
    List(String[]{“NETWORK/NETID”,“asc”},String[]{“INFODATA/NAME”,“asc”},String[]{“SOURCE/SYSTEM”,“asc”})

  • 然后您需要编写一个方法,该方法接受两个参数:一个JSONObject和一个字符串(属性的路径),并返回该属性的值

    我不会为您编写此方法。请记住JSON的
    .get(key)
    方法。Simple始终生成
    对象
    。使用此签名编写方法:

    public String findSortValue(JSONObject doc, String path){
        // split the path
        // find the parent
        // cast it  (parent was returned as an Object of type Object)
        // find the child
        return value;
    }
    
  • 编写一个通用的单个比较器(一次只比较一个排序属性的值),并确定它是Int、Date还是常规字符串。我将把它作为常规方法编写,以便以后更容易合并所有内容。由于您对此有很多问题,我举了一个示例:

    int individualComparator(String s1, String s2){
    int compResult = 0;
    try{
        int numeric1 = Integer.parseInt(s1);
        int numeric2 = Integer.parseInt(s2);
        compResult = numeric1 - numeric2; // if this point was reached both values could be parsed
    } catch (NumberFormatException nfe){
        // if the catch block is reached they weren't numeric
        try{
            DateTime date1 = DateTime.parse(s1);
            DateTime date2 = DateTime.parse(s2);
            compResult = date1.compareTo(date2); // compareTo method of joda.time, the library I'm using
        } catch (IllegalArgumentException iae){
            //if this catch block is reached they weren't dates either
            compResult = s1.compareTo(s2);
        }
    }
    return compResult;
    
    })

  • 编写一个综合所有内容的总体比较器

    Comparator<JSONObject> overAllComparator = (jsonObj1, jsonObj2) -> {
        List<String[]> sortValuesList = sortParams.stream()
            .map(path -> new String[]{ findValueByName(jsonObj1, path), findValueByName(jsonObj2, path) } )
            .collect(Collectors.toList());
    
    //assuming we always have 3 attributes to sort on
    int comp1 = individualComparator(sortValuesList.get(0)[0], sortValuesList.get(0)[1]);
    int comp2 = individualComparator(sortValuesList.get(1)[0], sortValuesList.get(1)[1]);
    int comp3 = individualComparator(sortValuesList.get(2)[0], sortValuesList.get(2)[1]);
    
    int result = 0;
    if (comp1 != 0){
        result = comp1;
    } else if (comp2 != 0){
        result = comp2;
    } else{
        result = comp3;
    }
    return result;
    };
    
    Comparator-overAllComparator=(jsonObj1,jsonObj2)->{
    列表sortValuesList=sortParams.stream()
    .map(路径->新字符串[]{findValueByName(jsonObj1,路径),findValueByName(jsonObj2,路径)})
    .collect(Collectors.toList());
    //假设我们总是有3个属性进行排序
    int comp1=单个比较器(sortValuesList.get(0)[0],sortValuesList.get(0)[1]);
    int comp2=单个比较器(sortValuesList.get(1)[0],sortValuesList.get(1)[1]);
    int comp3=单个比较器(sortValuesList.get(2)[0],sortValuesList.get(2)[1]);
    int结果=0;
    如果(comp1!=0){
    结果=comp1;
    }否则如果(comp2!=0){
    结果=comp2;
    }否则{
    结果=comp3;
    }
    返回结果;
    };
    
  • 此比较器采用lambda风格编写,以获取更多信息

    首先,它获取我们在步骤1中创建的排序图的有序列表,并为每个排序图返回一个数组,其中位置0的值为
    jsonObj1
    ,位置1的值为
    jsonObj2
    ,并将其收集在
    sortValuesList
    中。然后,对于每个要排序的属性,它得到
    individualComparator的结果de>method。然后它沿着这一行,作为整体比较的结果返回第一个没有结果为0的值(当比较器结果为0时,两个值相等)

    现在唯一缺少的是请求中的asc/desc值。您可以通过链接
    int comp1=individualComparator(sortValuesList.get(0)[0],sortValuesList.get(0)[1]);
    来添加它,如果字符串等于“desc”,则使用一个简单的方法获取int&a字符串并将int乘以-1。(请记住,在
    sortparms
    中,我们在数组的位置1添加了
    order
    的值)


    由于我们创建的第一个列表,
    sortparms
    是根据请求中指示的优先级排序的,并且我们总是按照此列表的顺序执行所有操作,因此结果是按此顺序进行多重排序。它是通用的,将由请求中的
    returnParams
    的内容动态确定。您可以将其应用于您r使用在注释中的附加问题和说明中的附加信息后编辑的
    Collections.sort()

    列出JSONObject


    要获得解决方案,您需要执行以下几个步骤:

  • 您希望根据请求中属性
    序列的值动态排序。因此,您需要解析那些
    returnParameters
    的名称并将它们按顺序排列。下面我将它们映射到一个列表,其中每个字符串[]都有
    名称
    顺序
    (asc/desc)。列表将使用
    序列的值进行排序

    List<String[]> sortParams = params.stream() // params is a List<JSONObject>
            .filter(json -> json.containsKey("sequence")) // filter those that have "sequence" attribute
            .sorted( sequence ) // sorting using Comparator called sequence
            .map(jsonObj -> new String[]{jsonObj.get("name").toString(), jsonObj.get("order").toString()} )
            .collect(Collectors.toList());
    
    因此,对于您的示例,排序图看起来像:
    List(String[]{“NETWORK/NETID”,“asc”},St
    
    class ReturnParameterComparator implements Comparator<JSONObject> {
       private List<ReturnParameter> params; //set via constructor
    
       public int compare( JSONObject left, JSONObject right) {
         int result = 0;
         for( ReturnParameter p : params ) {
           //how exactly you get those values depends on the actual structure of your data and parameters
           String leftValueStr = left.get( p ); 
           String rightValueStr = right.get( p ); 
    
           switch( p.datatype ) {
             case "String": 
               result = String.compare( leftValueStr, rightValueStr );
               break;
             case "int": 
               //convert and then compare - I'll leave the rest for you 
           }
    
           //invert the result if the order is descending
           if( "desc".equals(p.order ) {
             result += -1;
           }
    
           //the values are not equal so return the order, otherwise continue with the next parameter
           if( result != 0 ) {
             return result;
           }
         }
    
         //at this point all values are to be considered equal, otherwise we'd have returned already (from the loop body)
         return 0;
       }
    }