有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我的样本请求

 {
  "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
    },
   ]
 }

样本响应

下面是我动态生成的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"
     }
  }
 ]
}

问题陈述

我需要根据请求中的“returnParameters”进行多级排序,这是动态的。。。 “order”表示升序(或降序),sequence表示排序的优先级,如(sql查询中的group by)

代码

Map<String,Object> documentList = new HashMap<String,Object>();
JSONObject jsonObject= new JSONObject(response.getContent());

答复。getContent()->;只不过它包含上述映射格式的json响应

Now I converting the map to list of json object

JSONArray jsonArray= (JSONArray)jsonObject.get("documents");
ArrayList<JSONObject> list = new ArrayList<>();
for(int i=0;i<jsonArray.length();i++){
 list.add((JSONObject) jsonArray.get(i));
 }
 Collections.sort(list, new ResponseSorter());
 public class ResponseSorter implements Comparator<JSONObject> {
  @Override
  public int compare(JSONObject o1,JSONObject o2){
  String s1= (String)((JSONObject) o1.get("NETWORK")).get("NETID");
  String s2= (String)((JSONObject) o2.get("NETWORK")).get("NETID");
  int i1=Integer.parseInt(s1);
  int i2=Integer.parseInt(s2);
  return i1-i2;
  }
 }

我被困在这里继续前进。为整数比较器创建了一个。我是否应该为每种数据类型创建新的数据类型?而且 我需要通过解析“retunrParameters”动态构造复合比较器,下面的示例是硬编码的,如何动态创建

(String)((JSONObject) o1.get("NETWORK")).get("NETID"); -> this should be dynamically framed , since "returnParameters" are also dynamic in nature.[NETWORK & NETID may not be come in another request],so my comparator should be capable enough to frame the keys in runtime

有人能帮我在运行时创建复合比较器进行排序吗

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


共 (3) 个答案

  1. # 1 楼答案

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


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

    1. 您希望排序基于请求中的属性sequence的值是动态的。因此,您需要解析这些returnParameters的名称并将它们按顺序排列。下面我将它们映射到一个列表,其中每个字符串[]都有nameorder(asc/desc)。列表将使用sequence的值排序:

      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());
      

    在此之前,首先将请求中的returnParameters数组中的对象映射到列表。然后,流由1处理。过滤JSONObject以仅保留那些具有propsequence的对象,2。使用下面的comparator对JSONObject进行排序。3.从每个JSONObject获取“name”&;“order”并将其放入字符串[],4。用这些数组生成一个列表。此列表将按照优先级为1的属性的顺序排列,然后是优先级为2的属性,以此类推,因此它的排列方式将与您希望最终对JSONObject排序的方式相同

        Comparator<JSONObject> sequence = Comparator.comparingInt(
            jsonObj -> Integer.valueOf( jsonObj.get("sequence").toString() ) 
        );
    

    因此,在您的示例中,排序图看起来像:List( String[]{"NETWORK/NETID", "asc"}, String[]{""INFODATA/NAME", "asc"}, String[]{"SOURCE/SYSTEM", "asc"} )

    1. 然后需要编写一个方法,该方法接受两个参数:一个JSONObject和一个字符串(属性的路径),并返回该属性的值。最初我建议您使用JSONAware接口,然后找出子类,但现在让我们先忘掉它

      我不会为你写这个方法。请记住,JSON的.get(key)方法。Simple总是产生一个Object。使用此签名编写一个方法:

      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;
      }
      
    2. 编写一个通用的单个比较器(一次只比较一个排序属性的值),并确定它是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;
      

      }

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

        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;
        };
        

    这个比较器是用lambda风格编写的,有关详细信息https://www.mkyong.com/java8/java-8-lambda-comparator-example/

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

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

    因为我们制作的第一个列表sortParams是根据请求中指示的优先级排序的,并且我们总是按照这个列表的顺序做每件事,所以结果是按照这个顺序进行多重排序。它是通用的&;将由请求中returnParams的内容动态确定。您可以使用Collections.sort()将其应用于JSONObject列表

  2. # 2 楼答案

    我的建议:了解:

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

    如果需要教程:https://www.baeldung.com/java-8-comparator-comparing

  3. # 3 楼答案

    在您的例子中,提供排序参数的简单比较器可能比一堆嵌套比较器更容易理解

    基本上你会这样做:

    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;
       }
    }
    

    请注意,这只是一个存根,让您开始。您需要添加很多内容:

    • 如何正确使用参数从json对象提取值
    • 如何根据类型转换数据
    • 如何处理空值、丢失或不兼容的数据(例如,如果一个值应排序为“int”,但无法解析)

    添加所有这些对于这个问题的范围来说太多了,这取决于您的数据和需求