使用Java 8流形成特定列表

9
我目前正在参与一个Java项目,在其中我有一个字符串列表,并希望使用流将它们格式化为特定的格式。
例如:
输入:[nom,contains,b,and,prenom,contains,y,and,age,>=,1,and,age,<=,100] 输出:
[
{key:"nom",
operation:"contains",
value:"b"
},
{
key:"prenom",
operation:"contains",
value:"y"
},
{
key:"age",
operation:">=",
value: 1
},
{
key:"age",
operation:"<=",
value: 1000
}]

我编写了一个非常基础的代码,没有使用数据流:

List filter = [nom, contains, b, and, prenom, contains, y, and, age, >=, 1, and, age, <=, 100]
    List<SearchCriteria> formedFilter = new ArrayList<>();
    SearchCriteria sc = new SearchCriteria();
    if(filter != null){
        for(int i = 0 ;i< filter.size();i++){
            if(i % 4 ==0){
                sc.setKey((String) filter.get(i));
            }else if(i % 4 == 1){
                sc.setOperation((String) filter.get(i));

            }else if(i % 4 ==2){
                sc.setValue(filter.get(i));
                formedFilter.add(sc);

            }else{
                sc = new SearchCriteria();
            }
        }
    }

搜索条件类(SearchCriteria Class)
public class SearchCriteria {
    private String key;
    private String operation;
    private Object value;

    public SearchCriteria() {
    }

    public SearchCriteria(String key, String operation, Object value) {
        this.key = key;
        this.operation = operation;
        this.value = value;
    }

   // getters and setters
}

索引为3、7和11的元素始终是“and”,还是可能是例如“or”或其他布尔运算? - fps
2
@FedericoPeraltaSchaffner,它们可以是“和/或”,但目前我不需要。 - Wassim Makni
2个回答

4

如果要使用Java 8版本的Aomine's answer,您可以使用以下代码:

List<SearchCriteria> formedFilter = IntStream.iterate(0, i -> i + 4)
            .limit(filter.size() / 4 + 1) // + 1 to consider the last group as well
            .mapToObj(i -> new SearchCriteria(filter.get(i), filter.get(i + 1), filter.get(i + 2)))
            .collect(Collectors.toList());

另外,类似于 Holger 的建议,你可以使用 IntStream 的 rangeClosed API,例如:

List<SearchCriteria> formedFilter2 = IntStream.rangeClosed(0, filter.size() / 4)
        .map(i -> i * 4)
        .mapToObj(i -> new SearchCriteria(filter.get(i), filter.get(i + 1), filter.get(i + 2)))
        .collect(Collectors.toList());

2
顺便提一下,由于在这里放置limit是无关紧要的,因此我会立即将它链接到iterate,因为它在语义上更接近,并且使迭代逻辑更容易理解。 - Holger
@Holger 我只是将短路操作更靠近终端操作,顺序并不重要,这是我的理解。 - Naman
1
@nullpointer 对,正如我所说的,limit 的位置在这里并不重要,所以只是一个风格问题。我理解你强调结果列表的大小的观点,但我仍然认为迭代逻辑更重要(考虑到 4 的出现)。 - Holger
@WassimMakni 是的,你说得对,那是因为我认为操作是由4个字符串组成的一组,而你的情况则会少一个用于最后一个操作。 - Naman
2
@nullpointer 我认为将 .limit(filter.size() / 4 + 1) 替换为 .limit(filter.size() / 4) 可以正确地完成任务。 - Wassim Makni
2
@WassimMakni 是的,Holger建议的使用 range.. API 的方式更加简洁。 - Naman

2

使用JDK 9,您可以做以下事情:

IntStream.iterate(0, i -> i < source.size(), i -> i + 4)
         .mapToObj(x -> new SearchCriteria(source.get(x), source.get(x + 1), source.get(x + 2)))
         .collect(toList());

2
@WassimMakni 这对于Java 8不起作用,但是您可以将 iterate(0, i -> i < source.size(), i -> i + 4) 替换为 range(0, source.size()/4).map(i -> i*4),这甚至可能更有效率。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接