I wrote some code to filter a list in Java and I think there must be a much better way of doing it...
Essentially I have a web page with a jqGrid and I am passing the filtering parameters into the java back end and trying to duplicate them. I have done this by making parsing the rule json into a List of Rule objects which contain field name, condition to be applied and condition (data).
so something like
public class Rule {
private String field;
private String op;
private String data;
...
At the moment strings are filtered on a contains and numbers by >, <, >= and <= although the string condition may change.
I wrote some very very quick code with loops and a remove list to avoid List modification issues. I must stress that this is awful and only here as a kind of pseudo code so that it shows what I'm trying to do...
private List<RowObject> ApplyjqTableFilter
(List<RowObject> unfilteredList, List<Rule> filterRules) {
List<RowObject> filteredList = unfilteredList;
List<RowObject> removeList = new ArrayList<>();
Boolean addedFlag = false;
for (RowObject cpsr : unfilteredList){
addedFlag = false;
for (Rule r : filterRules){
switch (r.getField()) {
case "ref" :
if (!cpsr.getRef().contains(r.getData().toLowerCase()))
removeList.add(cpsr);
addedFlag = true;
break;
...
similar cases for other String fields
...
case "Amount" :
switch (r.getOp()) {
case "lt":
if(cpsr.getAmount() >= Double.parseDouble(r.getData())){
removeList.add(cpsr);
addedFlag = true;
}
break;
case "gt":
if(cpsr.getAmount() <= Double.parseDouble(r.getData())){
removeList.add(cpsr);
addedFlag = true;
}
break;
case "le":
if(cpsr.getAmount() > Double.parseDouble(r.getData())){
removeList.add(cpsr);
addedFlag = true;
}
break;
case "ge":
if(cpsr.getAmount() < Double.parseDouble(r.getData())){
removeList.add(cpsr);
addedFlag = true;
}
break;
}
...
other value field cases
...
}
if (addedFlag==true) break;
}
}
}
filteredList.removeAll(removeList);
return filteredList;
}
So once I had validated that this was the business requirement (lets try and justify this 'code' as Agile ;-) I tried to turn this into proper code. So far I have got to here but I think I am still missing a trick, probably approaching it from the wrong direction ? It works well in a timely and consistent way but it seems very clunky ?
private List<RowObject> ApplyjqTableFilter
(List<RowObject> unfilteredList, List<Rule> filterRules) {
List<RowObject> filteredList = unfilteredList;
for (Rule r : filterRules){
switch (r.getField()) {
case "ref" :
filteredList = filteredList.stream()
.filter(cl -> cl.getRef().contains(r.getData().toLowerCase()))
.collect(Collectors.toList());
break;
...
similar String cases for other fields
...
case "Amount" :
switch (r.getOp()) {
case "lt":
filteredList = filteredList.stream()
.filter(cl -> cl.getAmount() < Double.parseDouble(r.getData()))
.collect(Collectors.toList());
break;
case "gt":
filteredList = filteredList.stream()
.filter(cl -> cl.getAmount() > Double.parseDouble(r.getData()))
.collect(Collectors.toList());
break;
case "le":
filteredList = filteredList.stream()
.filter(cl -> cl.getAmount() <= Double.parseDouble(r.getData()))
.collect(Collectors.toList());
break;
case "ge":
filteredList = filteredList.stream()
.filter(cl -> cl.getAmount() >= Double.parseDouble(r.getData()))
.collect(Collectors.toList());
break;
}
break;
...
other value field cases
...
}
}
return filteredList;
}
Any suggestions ?