Java 8 分区列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30995763/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 17:56:17  来源:igfitidea点击:

Java 8 partition list

javajava-8partitioning

提问by Beri

Is it possible to partition a List in pure Jdk8 into equal chunks (sublists).

是否可以将纯 Jdk8 中的列表划分为相等的块(子列表)。

I know it is possible using Guava Listsclass, but can we do it with pure Jdk? I don't want to add new jars to my project, just for one use case.

我知道可以使用 Guava Lists类,但是我们可以使用纯 Jdk 来实现吗?我不想在我的项目中添加新的 jar,只是为了一个用例。

SOLUTONS:

解决方案

The best solution till now was presented by tagir-valeev:

迄今为止最好的解决方案是由tagir-valeev提出的:

I have also found three other possibilities, but they are ment for only few cases:

我还发现了其他三种可能性,但它们仅适用于少数情况:

1.Collectors.partitioningBy() to split the list into 2 sublists – as follows:

1.Collectors.partitioningBy() 将列表拆分为 2 个子列表——如下:

intList.stream().collect(Collectors.partitioningBy(s -> s > 6));
    List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values());

2.Collectors.groupingBy() to split our list to multiple partitions:

2.Collectors.groupingBy() 将我们的列表拆分为多个分区:

 Map<Integer, List<Integer>> groups = 
      intList.stream().collect(Collectors.groupingBy(s -> (s - 1) / 3));
    List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values());

3.Split by separator:

3.按分隔符拆分:

List<Integer> intList = Lists.newArrayList(1, 2, 3, 0, 4, 5, 6, 0, 7, 8);

    int[] indexes = 
      Stream.of(IntStream.of(-1), IntStream.range(0, intList.size())
      .filter(i -> intList.get(i) == 0), IntStream.of(intList.size()))
      .flatMapToInt(s -> s).toArray();
    List<List<Integer>> subSets = 
      IntStream.range(0, indexes.length - 1)
               .mapToObj(i -> intList.subList(indexes[i] + 1, indexes[i + 1]))
               .collect(Collectors.toList());

4.Using Streams + counter source:

4.使用流+计数器

final List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7);
final int chunkSize = 3;
final AtomicInteger counter = new AtomicInteger();

final Collection<List<Integer>> result = numbers.stream()
    .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / chunkSize))
    .values();

采纳答案by Beri

I have tried my own solution with a custom made Collector. I hope someone will find it useful, or help me improve it.

我已经使用定制的收集器尝试了我自己的解决方案。我希望有人会觉得它有用,或者帮助我改进它。

class PartitioningCollector<T> implements Collector<T, List<List<T>>, List<List<T>>> {

        private final int batchSize;
        private final List<T> batch;

        public PartitioningCollector(int batchSize) {
            this.batchSize = batchSize;
            this.batch = new ArrayList<>(batchSize);
        }

        @Override
        public Supplier<List<List<T>>> supplier() {
            return LinkedList::new;
        }

        @Override
        public BiConsumer<List<List<T>>, T> accumulator() {
            return (total, element) -> {
                batch.add(element);
                if (batch.size() >= batchSize) {
                    total.add(new ArrayList<>(batch));
                    batch.clear();
                }
            };
        }

        @Override
        public BinaryOperator<List<List<T>>> combiner() {
            return (left, right) -> {
                List<List<T>> result = new ArrayList<>();
                result.addAll(left);
                result.addAll(left);
                return result;
            };
        }

        @Override
        public Function<List<List<T>>, List<List<T>>> finisher() {
            return result -> {
                if (!batch.isEmpty()) {
                    result.add(new ArrayList<>(batch));
                    batch.clear();
                }
                return result;
            };
        }

        @Override
        public Set<Characteristics> characteristics() {
            return emptySet();
        }
    }

回答by Robert

That can be done easily using the subList()method:

这可以使用以下subList()方法轻松完成:

List<String> collection = new ArrayList<>(21);
// fill collection
int chunkSize = 10;
List<List<String>> lists = new ArrayList<>();
for (int i = 0; i < collection.size(); i += chunkSize) {
    int end = Math.min(collection.size(), i + chunkSize);
    lists.add(collection.subList(i, end));
}

回答by chabbi aissa

Try using this code, it uses Java 8:

尝试使用此代码,它使用 Java 8:

public static Collection<List<Integer>> splitListBySize(List<Integer> intList, int size) {

    if (!intList.isEmpty() && size > 0) {
        final AtomicInteger counter = new AtomicInteger(0);
        return intList.stream().collect(Collectors.groupingBy(it -> counter.getAndIncrement() / size)).values();
    }
    return null;
}

回答by Mohamed.Abdo

private final String dataSheet = "103343262,6478342944, 103426540,84528784843, 103278808,263716791426, 103426733,27736529279, 
103426000,27718159078, 103218982,19855201547, 103427376,27717278645, 
103243034,81667273413";

    final int chunk = 2;
    AtomicInteger counter = new AtomicInteger();
    Collection<List<String>> chuncks= Arrays.stream(dataSheet.split(","))
            .map(String::trim)
            .collect(Collectors.groupingBy(i->counter.getAndIncrement()/chunk))
            .values();

result:

结果:

pairs =
 "103218982" -> "19855201547"
 "103278808" -> "263716791426"
 "103243034" -> "81667273413"
 "103426733" -> "27736529279"
 "103426540" -> "84528784843"
 "103427376" -> "27717278645"
 "103426000" -> "27718159078"
 "103343262" -> "6478342944"

We need to group each 2 elements into key, value pairs, so will partion the list into chunks of 2, (counter.getAndIncrement() / 2) will result same number each 2 hits ex:

我们需要将每 2 个元素分组为键、值对,因此将列表分成 2 个块,(counter.getAndIncrement() / 2) 将导致每 2 个命中相同的数字,例如:

IntStream.range(0,6).forEach((i)->System.out.println(counter.getAndIncrement()/2));
prints:
0
0
1
1
2
2

You may ajust chunk sizee to partition lists sizes.

您可以将块大小调整为分区列表大小。