Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
93 views
in Technique[技术] by (71.8m points)

java - Filtering between specific values creating sublists

I have this list:

List<String> names= Arrays.asList(new String[]{"Tom", "louis", "martha", "Tom", "john", "Carol", "Tom", "Simon"});

I want to create three different lists where I put the values between Tom word:

"Tom", "louis", "martha";
"Tom", "john", "Carol";
"Tom", "Simon"

I was doing with indexes in a traditional way

My way was just;

List<Integer> positionsWithTom = new ArrayList<>();

for(int i=0; i<names.size; i++){
...
positionsWithTom = [0,3,6]
}

and then put the values between in different lists

There is not a much elegant by doing this, maybe with stream filtering somehow?

question from:https://stackoverflow.com/questions/65600033/filtering-between-specific-values-creating-sublists

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I don't believe this easily lends itself to streams. Nor would a stream approach be any more clear in expressing the problem statement than a simple loop.

As long as you don't care what order the sublists are in, it is pretty straight forward using List.lastIndexOf and a while loop. Note that since this chews up the original list and the fact that these sublists don't overlap, there is no chance of the sublists being altered by changes to the original list or by each other (unless a reference to the original exists). But one can always pass the sublist as an argument to the ArrayList constructor if this is a concern.

List<String> names = new ArrayList<>(List.of("Tom", "louis",
        "martha", "Tom", "john", "Carol", "Tom", "Simon"));

List<List<String>> lists = new ArrayList<>();
    
int start;
while ((start = names.lastIndexOf("Tom")) >= 0) {
    ists.add(names.subList(start, names.size()));
    names = names.subList(0, start);
}
    
lists.forEach(System.out::println);

Prints

[Tom, Simon]
[Tom, john, Carol]
[Tom, louis, martha]

Note that the order can be reversed by specifying an index of 0 in the add method. But that can be expensive for ArrayLists due to the copying. A LinkedList would alleviate that expense for a bit of overhead.

And just for completion, here is my stream solution.

  • first, stream the names in successive sublists based on where Tom is located. So the first list contains all the names, the second, all but the last "Tom" grouping, and so forth.
  • Then for each of those sublists, pick off the last sublist starting with Tom from the end.
  • and put the lists in a collection.
List<List<String>> result = Stream.iterate(
            names,
            n -> n.size() > 0 && n.lastIndexOf("Tom") >= 0,
            n -> n.subList(0, n.lastIndexOf("Tom")))
        .map(n -> n.subList(n.lastIndexOf("Tom"), n.size()))
        .collect(Collectors.toList());

result.forEach(System.out::println);

Prints

[Tom, Simon]
[Tom, john, Carol]
[Tom, louis, martha]

I still prefer the while loop solution as I think it is cleaner and more succinct. Someone more proficient in streams could probably do it better.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...