Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<String> get count of all elements ending with one of strings from another list

Let's say I have one list with elements like:

List<String> endings= Arrays.asList("AAA", "BBB", "CCC", "DDD");

And I have another large list of strings from which I would want to select all elements ending with any of the strings from the above list.

List<String> fullList= Arrays.asList("111.AAA", "222.AAA", "111.BBB", "222.BBB", "111.CCC", "222.CCC", "111.DDD", "222.DDD");

Ideally I would want a way to partition the second list so that it contains four groups, each group containing only those elements ending with one of the strings from first list. So in the above case the results would be 4 groups of 2 elements each.

I found this example but I am still missing the part where I can filter by all endings which are contained in a different list.

Map<Boolean, List<String>> grouped = fullList.stream().collect(Collectors.partitioningBy((String e) -> !e.endsWith("AAA")));

UPDATE: MC Emperor's Answer does work, but it crashes on lists containing millions of strings, so doesn't work that well in practice.

like image 340
delica Avatar asked Sep 26 '19 09:09

delica


Video Answer


1 Answers

Update

This one is similar to the approach from the original answer, but now fullList is no longer traversed many times. Instead, it is traversed once, and for each element, the list of endings is searched for a match. This is mapped to an Entry(ending, fullListItem), and then grouped by the list item. While grouping, the value elements are unwrapped to a List.

Map<String, List<String>> obj = fullList.stream()
    .map(item -> endings.stream()
        .filter(item::endsWith)
        .findAny()
        .map(ending -> new AbstractMap.SimpleEntry<>(ending, item))
        .orElse(null))
    .filter(Objects::nonNull)
    .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toList())));

Original answer

You could use this:

Map<String, List<String>> obj = endings.stream()
    .map(ending -> new AbstractMap.SimpleEntry<>(ending, fullList.stream()
        .filter(str -> str.endsWith(ending))
        .collect(Collectors.toList())))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

It takes all endings and traverses the fullList for elements ending with the value.

Note that with this approach, for each element it traverses the full list. This is rather inefficient, and I think you are better off using another way to map the elements. For instance, if you know something about the structure of the elements in fullList, then you can group it immediately.

like image 111
MC Emperor Avatar answered Sep 28 '22 02:09

MC Emperor