【问题标题】:Java 8 partition listJava 8 分区列表
【发布时间】:2015-09-08 20:06:39
【问题描述】:

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

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

解决方案

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

我也找到了three other possibilities,但只针对少数情况:

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() 将我们的列表拆分为多个分区:

 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.按分隔符分割:

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.使用流+计数器source

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();

【问题讨论】:

  • 你可以看看 Guava 的源代码并做相应的操作...?
  • 用纯 java 写一个函数不是问题,但是 JDK8 有一些很棒的特性,可以对集合进行流式处理和操作,我认为它会比编写自己的代码更快。但这只是我的假设。
  • 我将其标记为可能重复,因为那里也提供 Java-8 解决方案。
  • 是的,我看到了这个问题,但是我错过了 Jdk8 解决方案,谢谢:)
  • 也讨论过here

标签: java java-8 partitioning


【解决方案1】:

这可以使用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));
}

【讨论】:

    【解决方案2】:

    尝试使用此代码,它使用 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;
    }
    

    【讨论】:

      【解决方案3】:

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

      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();
              }
          }
      

      【讨论】:

        【解决方案4】:
        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();
        

        结果:

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

        我们需要将每 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
        

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

        【讨论】:

          【解决方案5】:

          Guava Lists 类有一个 partition() 方法可以做到这一点。见https://guava.dev/releases/21.0/api/docs/com/google/common/collect/Lists.html#partition-java.util.List-int-

          【讨论】:

          • 这个问题的重点是不使用任何外部库。
          • 您好,欢迎来到 StackOverflow。请在回答之前阅读问题。它说他想使用纯Jdk8。这是,没有像 Guava 这样的库。
          猜你喜欢
          • 1970-01-01
          • 2014-07-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-12
          • 1970-01-01
          • 2017-12-24
          相关资源
          最近更新 更多