Home > Mobile >  Iterate over two Lists of Lists with IntStream instead of streams
Iterate over two Lists of Lists with IntStream instead of streams

Time:10-15

I am trying to use streams in order to iterate over two lists of lists in order to verify if the inner lists sizes are the same for the same index. I have managed to achieve this using streams, but I have to rewrite using an IntStream and mapToObj.

My current approach is:

List<List<String>> a = config.getStrips();
List<List<Integer>> b = slotMachineConfig.getWeights();

a.stream()
 .filter(first ->
    b.stream()
     .allMatch(second -> second.size() == first.size())
 )
 .findFirst()
 .orElseThrow(InvalidConfigException::new);

The problem is that I cannot be sure that the sizes will correspond for the big lists, so I have to rewrite this using IntStream and also using indexes for each list.

What I have so far, but does not work looks like this, I am trying to write a "validate" function in order to verify the inner lists, but it seems like I get an error there saying "no instance of type variable U exist so that void conforms to U".

IntStream.range(0, a.size())
    .mapToObj(i -> validate(i, a.get(i), b.get(i)))
    .findFirst()
    .orElseThrow(SlotMachineInvalidConfigException::new);

public void validate(int index, List<String> firstList, List<Integer> secondList) {

How can I rewrite my method using IntStream and mapToObj, can anyone help me?

CodePudding user response:

If I understand correctly, I think something like this would work:

List<List<String>> a = config.getStrips();
List<List<Integer>> b = slotMachineConfig.getWeights();

if (a.size() != b.size()) throw new InvalidConfigException();
boolean allTheSame = IntStream.range(0, a.size())
    .map(i -> a.get(i).size() - b.get(i).size())
    .allMatch(diff -> diff == 0);
if (!allTheSame) throw new InvalidConfigException();

CodePudding user response:

You have the right idea but you don't really need a separate validation function if you are just comparing sizes. Here's a working example that supports any list types:

public class ListSizeMatcher {
    public <T,S> boolean  sizeMatches(List<List<T>> list1, List<List<S>> list2) {
        return list1.size() == list2.size()
                && IntStream.range(0, list1.size())
                    .allMatch(i -> list1.get(i).size() == list2.get(i).size());
    }
    public static void main(String[] args) {
        ListSizeMatcher matcher = new ListSizeMatcher();
        System.out.println(matcher.sizeMatches(List.of(List.of(1)), List.of(List.of("a"), List.of("b"))));
        System.out.println(matcher.sizeMatches(List.of(List.of(1)), List.of(List.of("a", "b"))));
        System.out.println(matcher.sizeMatches(List.of(List.of(1, 2)), List.of(List.of("a", "b"))));
    }
}

Note that from a design perspective if each item in the list matches the corresponding item in a separate list you'd be better off creating a single class that contains both items.

CodePudding user response:

For the record, your validate function returns void but I'll assume it was meant to return a boolean

here is a more compact version

               List<List<String>> a = new LinkedList<>();
        List<List<Integer>> b = new LinkedList<>();
        boolean match = IntStream.range(0, a.size())
                .mapToObj(i -> a.get(i).size() == b.get(i).size())
                .reduce(Boolean::logicalAnd).orElseThrow(InvalidConfigException::new);
        if (!match) {
            throw new InvalidConfigException();
        }

Alternative:

     List<List<String>> a = new LinkedList<>();
        List<List<Integer>> b = new LinkedList<>();
        if (IntStream.range(0, a.size()).filter(i -> a.get(i).size() != b.get(i).size()).count() > 0){
            throw new InvalidConfigException();
        };

At the end of the day it only takes 1 to be different and fail.

CodePudding user response:

The error means that the validate method cannot be void and it is expected to return some valid value (possibly boolean).

If the inner lists are supposed to have the equal sizes to be valid, the check may look as follows:

// assuming the sizes of outer lists are equal
boolean allSizesEqual = IntStream.range(0, a.size())
    .allMatch(i -> a.get(i).size() == b.get(i).size());
if (!allSizesEqual) {
    throw new InvalidConfigException("Not all sizes are valid");
}

If there's a need to find specific indexes where a discrepancy is detected:

List<Integer> badIndexes = IntStream.range(0, a.size())
    .filter(i -> a.get(i).size() != b.get(i).size()) // IntStream
    .boxed() // Stream<Integer>
    .collect(Collectors.toList());

if (!badIndexes.isEmpty()) {
    throw new InvalidConfigException("Different indexes found: "   badIndexes);
}

Or validate method could be fixed to return appropriate value for the filter:

boolean allItemsValid = IntStream.range(0, a.size())
    .allMatch(i -> listsAreValid(a.get(i), b.get(i)));
if (!allItemsValid) {
    throw new InvalidConfigException("Not all entries are valid");
}

public boolean listsAreValid(List<String> innerA, List<Integer> innerB) {
// any advanced logic
    return innerA.size() == innerB.size();
}
  • Related