Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding two similar arrays using streams

Let's say I have list of objects, each containing own array of Strings. I need to find objects that have most duplicates with given array. I can simply achive that by using some for loops, if and counters, but I want to do that using Java 8 streams. I really hope it is possible.

@Test
public void test() {

    String mainArray[]  = {"a", "b", "c"};
    List<ElementsList> elems = new ArrayList<>();

    ElementsList a = new ElementsList(new String[]{"d", "e", "a"});
    ElementsList b = new ElementsList(new String[]{"b", "c", "d"});

    elems.add(a);
    elems.add(b);

    List<ElementsList> result = elems.stream()...;

    assertTrue(result.contains(b));
}

private class ElementsList {

    private String elements[];

    private ElementsList(String elements[]) {
        this.elements = elements;
    }

    public String[] getElements() {
        return elements;
    }
}
like image 570
Krzysztof Cybulski Avatar asked Sep 05 '17 10:09

Krzysztof Cybulski


People also ask

Can streams be used with arrays?

stream() method only works for primitive arrays of int[], long[], and double[] type, and returns IntStream, LongStream and DoubleStream respectively. For other primitive types, Arrays. stream() won't work.

What does arrays stream () do?

The stream(T[] array) method of Arrays class in Java, is used to get a Sequential Stream from the array passed as the parameter with its elements. It returns a sequential Stream with the elements of the array, passed as parameter, as its source.

How does stream detect duplicate values in a list?

Get the stream of elements in which the duplicates are to be found. For each element in the stream, count the frequency of each element, using Collections. frequency() method. Then for each element in the collection list, if the frequency of any element is more than one, then this element is a duplicate element.


2 Answers

I can think of this for example:

List<String> main = Arrays.asList(mainArray);
Stream.of(a, b)
            .map(x -> new AbstractMap.SimpleEntry<>(x, new ArrayList<>(new ArrayList<>(Arrays.asList(x.elements)))))
            .map(entry -> {
                entry.getValue().removeAll(main);
                entry.setValue(entry.getValue());
                return entry;
            })
            .sorted(Comparator.comparing(e -> e.getValue().size()))
            .map(Entry::getKey)
            .forEach(el -> System.out.println(Arrays.toString(el.elements)));

Basically put all the elements into a mutable List and do a removeAllof the ones from mainArray and sort the result based on the size of the remaining ones.

like image 82
Eugene Avatar answered Oct 04 '22 02:10

Eugene


Here's a straightforward approach:

import static java.util.Comparator.comparingLong;

Set<String> mainSet = new HashSet<>(Arrays.asList(mainArray));

ToLongFunction<ElementsList> countMatches = el -> 
        Arrays.stream(el.getElements())
            .filter(mainSet::contains)
            .count();

ElementsList result = elems.stream()
        .max(comparingLong(countMatches))
        .get(); // or throw if elems is empty
like image 20
Misha Avatar answered Oct 04 '22 03:10

Misha