Using java8 streams merge internal lists in a list

I want to merge internal lists using java8 threads for the following:

When

List<List<Integer>> mainList =  new ArrayList<List<Integer>>();
        mainList.add(Arrays.asList(0,1));
        mainList.add(Arrays.asList(0,1,2));
        mainList.add(Arrays.asList(1,2));
        mainList.add(Arrays.asList(3));

should be combined into

  [[0,1,2],[3]];       

And when

List<List<Integer>> mainList =  new ArrayList<List<Integer>>();
        mainList.add(Arrays.asList(0,2));
        mainList.add(Arrays.asList(1,4));
        mainList.add(Arrays.asList(0,2,4));
        mainList.add(Arrays.asList(3,4));      
        mainList.add(Arrays.asList(1,3,4));

should be combined into

 [[0,1,2,3,4]];                

This is what I did

static void mergeCollections(List<List<Integer>> collectionTomerge) {
    boolean isMerge = false;
    List<List<Integer>> mergeCollection = new ArrayList<List<Integer>>();

    for (List<Integer> listInner : collectionTomerge) {
        List<Integer> mergeAny = mergeCollection.stream().map(
                lc -> lc.stream().filter(listInner::contains)
        ).findFirst()
                .orElse(null)
                .collect(Collectors.toList());
    }
}

but I get this exception:

Exception in thread "main" java.lang.NullPointerException
at linqArraysOperations.LinqOperations.mergeCollections(LinqOperations.java:87)

Updated with my answer version

What I want to achieve but Tagir's excellent answer is not recursive

I am changing things a bit in Mikhaal to achieve this using Tagir's answer logic without a flat map

public static <T> List<List<T>> combineList(List<List<T>> argList) {
       boolean isMerge = false;
       List<List<T>> result = new ArrayList<>();

       for (List<T> list : argList) {
                                List<List<T>> mergedFound =
                                        result.stream()
                                        .filter(mt->list.stream().anyMatch(mt::contains))
                                        .map(
                                              t ->  Stream.concat(t.stream(),list.stream()).distinct()
                                              .collect(Collectors.toList())
                                             )
                                       .collect(Collectors.toList());

                //if(mergedFound !=null && ( mergedFound.size() > 0 &&  mergedFound.stream().findFirst().get().size() > 0 )){
        if(mergedFound !=null &&  mergedFound.size() > 0 && ){
                   result = Stream.concat(result.stream().filter(t->list.stream().noneMatch(t::contains)),mergedFound.stream()).distinct().collect(Collectors.toList());
                   isMerge = true;
                }
                else
                    result.add(list);

       }
       if(isMerge && result.size() > 1)
          return  combineList(result);
        return result;
    }
+4
source share
2 answers

Here is a very simple but not very effective solution:

static List<List<Integer>> mergeCollections(List<List<Integer>> input) {
    List<List<Integer>> result = Collections.emptyList();

    for (List<Integer> listInner : input) {
        List<Integer> merged = Stream.concat(
                // read current results and select only those which contain
                // numbers from current list
                result.stream()
                      .filter(list -> list.stream().anyMatch(listInner::contains))
                      // flatten them into single stream
                      .flatMap(List::stream),
                // concatenate current list, remove repeating numbers and collect
                listInner.stream()).distinct().collect(Collectors.toList());

        // Now we need to remove used lists from the result and add the newly created 
        // merged list
        result = Stream.concat(
                result.stream()
                      // filter out used lists
                      .filter(list -> list.stream().noneMatch(merged::contains)),
                Stream.of(merged)).collect(Collectors.toList());
    }
    return result;
}

, listInner , . , , [[1, 2], [4, 5], [7, 8]], listInner, [2, 3, 5, 7], [[1, 2, 3, 4, 5, 7, 8]] ( ). , listInner, , listInner merged. , merged, merged.

partitioningBy :

static List<List<Integer>> mergeCollections(List<List<Integer>> input) {
    List<List<Integer>> result = Collections.emptyList();

    for (List<Integer> listInner : input) {
        // partition current results by condition: whether they contain
        // numbers from listInner
        Map<Boolean, List<List<Integer>>> map = result.stream().collect(
                Collectors.partitioningBy(
                        list -> list.stream().anyMatch(listInner::contains)));

        // now map.get(true) contains lists which intersect with current
        //    and should be merged with current
        // and map.get(false) contains other lists which should be preserved 
        //    in result as is
        List<Integer> merged = Stream.concat(
                map.get(true).stream().flatMap(List::stream),
                listInner.stream()).distinct().collect(Collectors.toList());
        result = Stream.concat(map.get(false).stream(), Stream.of(merged))
                       .collect(Collectors.toList());
    }
    return result;
}

map.get(true) , listInner map.get(false), , .

, , , , List<TreeSet<Integer>> , .

+5

, , List<List<Integer>>, mergeCollections, null, NullPointerException listInner::contains.

-, , , , . , :

public class Combiner {

    public static void main(String[] args) {
        List<List<Integer>> mainList = new ArrayList<>();
        mainList.add(Arrays.asList(1, 2));
        mainList.add(Arrays.asList(4, 5));
        mainList.add(Arrays.asList(7, 8));
        mainList.add(Arrays.asList(6, 19));

        mainList.add(Arrays.asList(2, 3, 5, 7));

        System.out.println(combineList(new ArrayList<>(mainList)));
        List<List<Integer>> result = mergeCollections(new ArrayList<>(mainList));
        System.out.println(result);

    }

    public static <T> List<List<T>> combineList(List<List<T>> argList) {
        List<List<T>> result = new ArrayList<>();
        for (List<T> list : argList) {
            //Copy the given list
            List<T> addedList = new ArrayList<>(list);
            result.add(addedList);
            for (List<T> otherList : argList) {
                if (list.equals(otherList)) continue;
                //If at least one element is shared between the two lists
                if (list.stream().anyMatch(otherList::contains)) {
                    //Add all elements that are exclusive to the second list
                    addedList.addAll(otherList.stream().map(t -> addedList.contains(t) ? null : t)
                            .filter(t -> t != null).collect(Collectors.toList()));
                }
            }
        }
        List<List<T>> del = new ArrayList<>();
        for (int i = 0; i < result.size(); i++) {
            for (int j = i + 1; j < result.size(); j++) {
                List<T> list = result.get(j);
                if (listEqualsUnOrdered(list, result.get(i))) {
                    //Modified this
                    del.add(result.get(i));
                }
            }
            //Can't use listIterator here because of iterating starting at j + 1
            result.removeAll(del);
        }
        //Recursion
        if (!result.equals(argList)) {
            result = combineList(result);
        }
        return result;
    }

    private static <T> boolean listEqualsUnOrdered(List<T> list1, List<T> list2) {
        if (list1.size() != list2.size()) return false;
        List<T> testOne = new ArrayList<>(list1);
        testOne.removeAll(list2);
        boolean testOnePassed = (testOne.size() == 0);
        List<T> testTwo = new ArrayList<>(list2);
        testTwo.removeAll(list1);
        if (testTwo.size() == 0 && testOnePassed) return true;
        return false;
    }
}

, , "", .. , . , , .

, .

+1

Source: https://habr.com/ru/post/1669424/


All Articles