복붙노트

[SCALA] 자바 8 요소의 고정 된 수의 여러 목록으로 분할 목록

SCALA

자바 8 요소의 고정 된 수의 여러 목록으로 분할 목록

나는 스칼라 그룹화 기능과 유사 뭔가 할 수 있습니다. 기본적으로, 한 번에 두 요소를 선택하고이를 처리합니다. 여기서 동일한위한 기준은 :

요소의 고정 된 수의 여러 목록으로 분할 목록

주면서 groupingBy 및 partitioningBy 등을 제공 않지만 그들 중 누구도 스칼라의 그룹화 기능으로 동일한 기능을 수행 할 것 없습니다. 모든 포인터를 감상 할 수있다.

해결법

  1. ==============================

    1.그것은 더 나은 그냥 스트림 API 자체에서 제공되는 작전과 같은 낮은 수준의 스트림 작업처럼 처리 문제 같은 소리. A (상대) 간단한 해결책처럼 보일 수 있습니다 :

    그것은 더 나은 그냥 스트림 API 자체에서 제공되는 작전과 같은 낮은 수준의 스트림 작업처럼 처리 문제 같은 소리. A (상대) 간단한 해결책처럼 보일 수 있습니다 :

    public static <T> Stream<List<T>> chunked(Stream<T> s, int chunkSize) {
        if(chunkSize<1) throw new IllegalArgumentException("chunkSize=="+chunkSize);
        if(chunkSize==1) return s.map(Collections::singletonList);
        Spliterator<T> src=s.spliterator();
        long size=src.estimateSize();
        if(size!=Long.MAX_VALUE) size=(size+chunkSize-1)/chunkSize;
        int ch=src.characteristics();
        ch&=Spliterator.SIZED|Spliterator.ORDERED|Spliterator.DISTINCT|Spliterator.IMMUTABLE;
        ch|=Spliterator.NONNULL;
        return StreamSupport.stream(new Spliterators.AbstractSpliterator<List<T>>(size, ch)
        {
            private List<T> current;
            @Override
            public boolean tryAdvance(Consumer<? super List<T>> action) {
                if(current==null) current=new ArrayList<>(chunkSize);
                while(current.size()<chunkSize && src.tryAdvance(current::add));
                if(!current.isEmpty()) {
                    action.accept(current);
                    current=null;
                    return true;
                }
                return false;
            }
        }, s.isParallel());
    }
    

    간단한 테스트 :

    chunked(Stream.of(1, 2, 3, 4, 5, 6, 7), 3)
      .parallel().forEachOrdered(System.out::println);
    

    장점은 다음 스트림 프로세싱, 예를 들어, 모든 항목의 전체 집합을 필요가 없다는 것입니다

    chunked(
        IntStream.range(0, 1000).mapToObj(i -> {
            System.out.println("processing item "+i);
            return i;
        }), 2).anyMatch(list->list.toString().equals("[6, 7]")));
    

    인쇄합니다 :

    processing item 0
    processing item 1
    processing item 2
    processing item 3
    processing item 4
    processing item 5
    processing item 6
    processing item 7
    true
    

    오히려 IntStream.range (0 1000) 1000 개의 항목을 처리보다. 이것은 또한 무한 소스 스트림을 사용 할 수 있습니다 :

    chunked(Stream.iterate(0, i->i+1), 2).anyMatch(list->list.toString().equals("[6, 7]")));
    

    당신이에 관심이 있다면 충분히 당신은 단순히 다음과 같은 작업을 사용할 수 있습니다, 오히려 이후의 스트림 작업을 적용하는 것보다 수집을 구체화 :

    List<Integer> list=Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    int listSize=list.size(), chunkSize=2;
    List<List<Integer>> list2=
        IntStream.range(0, (listSize-1)/chunkSize+1)
                 .mapToObj(i->list.subList(i*=chunkSize,
                                           listSize-chunkSize>=i? i+chunkSize: listSize))
                 .collect(Collectors.toList());
    
  2. ==============================

    2.당신은 구아바 라이브러리를 사용할 수 있습니다.

    당신은 구아바 라이브러리를 사용할 수 있습니다.

    목록 <정수> bigList = ... 목록 <일람 <정수 >> smallerLists = Lists.partition (bigList, 10);

  3. ==============================

    3.당신은 당신의 자신의 수집을 만들 수 있습니다. 이 같은:

    당신은 당신의 자신의 수집을 만들 수 있습니다. 이 같은:

    class GroupingCollector<T> implements Collector<T, List<List<T>>, List<List<T>>> {
        private final int elementCountInGroup;
    
        public GroupingCollector(int elementCountInGroup) {
            this.elementCountInGroup = elementCountInGroup;
        }
    
        @Override
        public Supplier<List<List<T>>> supplier() {
            return ArrayList::new;
        }
    
        @Override
        public BiConsumer<List<List<T>>, T> accumulator() {
            return (lists, integer) -> {
                if (!lists.isEmpty()) {
                    List<T> integers = lists.get(lists.size() - 1);
                    if (integers.size() < elementCountInGroup) {
                        integers.add(integer);
                        return;
                    }
                }
    
                List<T> list = new ArrayList<>();
                list.add(integer);
                lists.add(list);
            };
        }
    
        @Override
        public BinaryOperator<List<List<T>>> combiner() {
            return (lists, lists2) -> {
                List<List<T>> r = new ArrayList<>();
                r.addAll(lists);
                r.addAll(lists2);
                return r;
            };
        }
    
        @Override
        public Function<List<List<T>>, List<List<T>>> finisher() {
            return lists -> lists;
        }
    
        @Override
        public Set<Characteristics> characteristics() {
            return Collections.emptySet();
        }
    }
    

    그리고이 같은 방법으로 사용할 수 있습니다 :

        List<List<Integer>> collect = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).collect(new GroupingCollector<>(3));
        System.out.println(collect);
    

    인쇄합니다 :

  4. ==============================

    4.재귀 솔루션은 가능한 것리스트 수준의 목록을리스트를 변환

    재귀 솔루션은 가능한 것리스트 수준의 목록을리스트를 변환

    int chunkSize = 2;
    
    private <T> List<List<T>> process(List<T> list) {
        if (list.size() > chunkSize) {
            List<T> chunk = list.subList(0, chunkSize);
            List<T> rest = list.subList(chunkSize, list.size());
            List<List<T>> lists = process(rest);
            return concat(chunk, lists);
        } else {
            ArrayList<List<T>> retVal = new ArrayList<>();
            retVal.add(list);
            return retVal;
        }
    }
    
    private <T> List<List<T>> concat(List<T> chunk, List<List<T>> rest) {
        rest.add(0, chunk);
        return rest;
    }
    
  5. ==============================

    5.당신은 유사 자신의 컬렉터 피니셔를 작성할 수

    당신은 유사 자신의 컬렉터 피니셔를 작성할 수

    final List<String> strings = Arrays.asList("Hello", "World", "I", "Am", "You");
    final int size = 3;
    
    final List<List<String>> stringLists = strings.stream()
            .collect(Collectors.collectingAndThen(Collectors.toList(), new Function<List<String>, List<List<String>>>() {
                @Override
                public List<List<String>> apply(List<String> strings) {
                    final List<List<String>> result = new ArrayList<>();
                    int counter = 0;
                    List<String> stringsToAdd = new ArrayList<>();
    
                    for (final String string : strings) {
                        if (counter == 0) {
                            result.add(stringsToAdd);
                        } else {
                            if (counter == size) {
                                stringsToAdd = new ArrayList<>();
                                result.add(stringsToAdd);
                                counter = 0;
                            }
                        }
    
                        ++counter;
                        stringsToAdd.add(string);
                    }
    
                    return result;
                }
            }));
    
    System.out.println("stringLists = " + stringLists); // stringLists = [[Hello, World, I], [Am, You]]
    
  6. ==============================

    6.자바 8 스트림 API를 사용하여 간단한 버전 :

    자바 8 스트림 API를 사용하여 간단한 버전 :

    static <T> List<List<T>> partition(List<T> list, Integer partitionSize) {
        int numberOfLists = BigDecimal.valueOf(list.size())
            .divide(BigDecimal.valueOf(partitionSize), 0, CEILING)
            .intValue();
    
        return IntStream.range(0, numberOfLists)
            .mapToObj(it -> list.subList(it * partitionSize, Math.min((it+1) * partitionSize, list.size())))
            .collect(Collectors.toList());
    }
    
  7. from https://stackoverflow.com/questions/28210775/split-list-into-multiple-lists-with-fixed-number-of-elements-in-java-8 by cc-by-sa and MIT license