我的样品请求
{
"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响应的Map格式[每次根据请求参数,响应参数都会有所不同]
"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());
response.getContent()->没什么,但是它包含以上以Map格式的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;
}
}
我被困在这里以继续进行。为Integer比较器创建了一个,是否应该为每个dataType创建一个?也 我需要通过解析“ 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
答案 0 :(得分:1)
在评论中的其他问题和描述中的其他信息之后进行了编辑
您需要执行以下几个步骤才能找到解决方案:
您希望基于请求中属性sequence
的值进行动态排序。因此,您需要解析那些returnParameters
的名称,并将它们排序。在下面,我将它们映射到一个列表,其中每个String []都有name
和order
(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
数组中的对象映射到一个List。然后通过1.过滤JSONObjects以仅保留具有道具sequence
的对象来处理流。 ,2.使用下面的比较器对JSONObject进行排序。 3.从每个JSONObject中获取“名称”和“顺序”,并将它们放入String [],4.生成包含这些数组的列表。该列表将按照属性的顺序进行排序,首先是优先级1,然后是优先级2,依此类推,因此它的排序方式与您希望JSONObjects最终排序的方式相同。
Comparator<JSONObject> sequence = Comparator.comparingInt(
jsonObj -> Integer.valueOf( jsonObj.get("sequence").toString() )
);
因此,在您的示例中,sortParams看起来像:List( String[]{"NETWORK/NETID", "asc"}, String[]{""INFODATA/NAME", "asc"}, String[]{"SOURCE/SYSTEM", "asc"} )
然后,您需要编写一个包含两个参数的方法:JSONObject和String(属性的路径),并返回该属性的值。最初,我建议您使用JSONAware接口,然后找出该子类,但现在就让我们忘记它。
我不会为您编写此方法。请记住,JSON.Simple的.get(key)
方法总是产生一个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;
}
编写一个通用的单个比较器(一次只比较一个sort属性的值),并确定它是Int,Date还是常规String。我将其编写为常规方法,以便以后将所有内容组合起来会更容易。由于您对此有很多疑问,因此我举了一个例子:
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;
};
此比较器以lambda样式编写,以获取更多信息https://www.mkyong.com/java8/java-8-lambda-comparator-example/。
首先,它获取我们在步骤1中创建的sortParams的有序列表,并为每个数组返回一个数组,其中位置0的值为jsonObj1
,位置1的值为jsonObj2
并将其收集在sortValuesList
中。然后,对于每个要排序的属性,它都会得到individualComparator
方法的结果。然后,它沿线下降并作为整体比较的结果返回第一个不为0的值(当比较器的结果为0时,两个值相等)。
现在唯一缺少的是请求中的asc / desc值。您可以通过使用简单的方法将int comp1 = individualComparator(sortValuesList.get(0)[0], sortValuesList.get(0)[1]);
链接到sortParams
来添加它,该方法接受一个int和一个String,如果String等于“ desc”,则将int乘以-1。 (请记住,在order
中,我们在数组的位置1上添加了sortParams
的值。)
因为我们创建了第一个列表,所以returnParams
是根据请求中指示的优先级排序的,并且我们总是按照该列表的顺序进行所有操作,因此结果是按此顺序进行的多排序。它是通用的,将由请求中Collections.sort()
的内容动态确定。您可以使用> devtools::install_github("https://github.com/nwstephens/RStudioAMI.git")
Downloading GitHub repo nwstephens/RStudioAMI@master
✔ checking for file ‘/tmp/RtmpEH49ON/remotes33643b988bf8/nwstephens-RStudioAMI-8507ced/DESCRIPTION’
─ preparing ‘RStudioAMI’:
✔ checking DESCRIPTION meta-information ... OK
Warning in file(con, "r") :
cannot open file 'man': No such file or directory
ERROR
computing Rd index failed:cannot open the connection
Error in (function (command = NULL, args = character(), error_on_status = TRUE, :
System command error
答案 1 :(得分:1)
在您的情况下,一个带有sort参数的简单比较器可能比一堆嵌套的比较器更容易理解。
基本上,您会这样做:
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;
}
}
请注意,这只是一个入门指南。您需要添加很多内容:
添加所有这些内容对于此问题的范围而言可能太多,并且仍然取决于您的数据和要求。
答案 2 :(得分:0)
我的建议:了解以下信息:
Comparator.comparing
,可让您通过指定密钥提取器来构建比较器Comparator.thanComparing
,可让您链接多个比较器。仅当前辈说对象相等时,才调用链中后面的比较器如果需要的话,提供一个教程:https://www.baeldung.com/java-8-comparator-comparing