怎么在在 Java 中对List进行分区

1. 概述

在本文中,我们将说明如何将一个列表拆分为多个给定大小的子列表。

对于这个相对简单的操作,标准 Java 集合 API 竟然不支持它。幸运的是,GuavaApache-Commons 都提供了对应的 API 。

2. 使用 Guava 对 List 进行分区

Guava 通过Lists.partition 操作将 List 划分为指定大小 的子列表:

 

Java

代码解读

复制代码

List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); List<List<Integer>> subSets = Lists.partition(intList, 3); subSets.forEach(s -> log.info("{}", s)); List<Integer> lastPartition = subSets.get(2); List<Integer> expectedLastPartition = Lists.newArrayList(7, 8); Assertions.assertEquals(subSets.size(), 3); Assertions.assertEquals(lastPartition, expectedLastPartition);

下面是我们得到的输出结果:

 

java

代码解读

复制代码

[1, 2, 3] [4, 5, 6] [7, 8]

3. 使用 Guava 对集合进行分区

Guava 也可以对集合进行分区:

 

Java

代码解读

复制代码

Collection<Integer> intCollection = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); Iterable<List<Integer>> subSets = Iterables.partition(intCollection, 3); List<Integer> firstPartition = subSets.iterator().next(); List<Integer> expectedLastPartition = Lists.newArrayList(1, 2, 3); Assertions.assertEquals(firstPartition, expectedLastPartition);

请记住,分区是原始集合的子列表视图, 这意味着原始集合中的更改将反映在分区中:

 

Java

代码解读

复制代码

@Test public void givenListPartitioned_whenOriginalListIsModified_thenPartitionsChangeAsWell() { // Given List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); List<List<Integer>> subSets = Lists.partition(intList, 3); // When intList.add(9); // Then List<Integer> lastPartition = subSets.get(2); List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8, 9); assertThat(lastPartition, equalTo(expectedLastPartition)); }

4. 使用 Apache Commons Collections 对列表进行分区

Apache Commons Collections 的最新版本最近也添加了对列表分区的支持:

 

Java

代码解读

复制代码

@Test public void givenList_whenParitioningIntoNSublists_thenCorrect() { List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); List<List<Integer>> subSets = ListUtils.partition(intList, 3); List<Integer> lastPartition = subSets.get(2); List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8); assertThat(subSets.size(), equalTo(3)); assertThat(lastPartition, equalTo(expectedLastPartition)); }

Commons Collections 没有相应的选项来对原始集合进行分区, 类似于 Guava Iterables.partition。

最后,同样的警告也适用于此:生成的分区是原始列表的视图。

5. 使用Java8对列表进行分区

现在让我们看看如何使用 Java8 对我们的 List 进行分区。

5.1 收集器分区方式

我们可以使用Collectors.partitioningBy() 将列表拆分为 2 个子列表:

 

Java

代码解读

复制代码

@Test public void givenList_whenParitioningIntoSublistsUsingPartitionBy_thenCorrect() { List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); Map<Boolean, List<Integer>> groups = intList.stream().collect(Collectors.partitioningBy(s -> s > 6)); List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values()); List<Integer> lastPartition = subSets.get(1); List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8); assertThat(subSets.size(), equalTo(2)); assertThat(lastPartition, equalTo(expectedLastPartition)); }

注意:生成的分区不是主列表的视图,因此主列表发生的任何更改都不会影响分区。

5.2 收藏家分组方式

我们还可以使用Collectors.groupingBy() 将我们的列表分成多个分区:

 

Java

代码解读

复制代码

@Test public final void givenList_whenParitioningIntoNSublistsUsingGroupingBy_thenCorrect() { List<Integer> intList = Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8); Map<Integer, List<Integer>> groups = intList.stream().collect(Collectors.groupingBy(s -> (s - 1) / 3)); List<List<Integer>> subSets = new ArrayList<List<Integer>>(groups.values()); List<Integer> lastPartition = subSets.get(2); List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8); assertThat(subSets.size(), equalTo(3)); assertThat(lastPartition, equalTo(expectedLastPartition)); }

注意:与Collectors.partitioningBy() 一样, 生成的分区不会受到主列表更改的影响。

5.3 按分隔符拆分列表

我们还可以使用 Java8 按分隔符拆分我们的列表:

 

Java

代码解读

复制代码

@Test public void givenList_whenSplittingBySeparator_thenCorrect() { 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()); List<Integer> lastPartition = subSets.get(2); List<Integer> expectedLastPartition = Lists.<Integer> newArrayList(7, 8); assertThat(subSets.size(), equalTo(3)); assertThat(lastPartition, equalTo(expectedLastPartition)); }

注意:我们使用“0”作为分隔符。我们首先获取了 List 中所有“0”元素的索引,然后我们根据这些索引拆分了List

6. 结论

此处介绍的解决方案使用了额外的库,即 Guava 和 Apache Commons Collections。这两者都非常轻量级并且总体上非常有用,因此将其中之一放在类路径中是非常有意义的。但是,如果这不是一个选项,那么此处显示了仅 Java 的解决方案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java使用Spark SQL的mapPartitions方法,可以按照如下方式进行: 1. 首先,你需要创建一个JavaSparkContext对象和SQLContext对象。这两个对象的创建方式如下: ```java SparkConf conf = new SparkConf().setAppName("MapPartitionsExample").setMaster("local[*]"); JavaSparkContext sc = new JavaSparkContext(conf); SQLContext sqlContext = new SQLContext(sc); ``` 2. 接下来,你需要创建一个JavaRDD对象。在这个例子,我们创建一个包含四个元素的JavaRDD,每个元素都是一个字符串: ```java JavaRDD<String> rdd = sc.parallelize(Arrays.asList("apple", "banana", "cherry", "date"), 2); ``` 3. 然后,你需要定义一个函数,该函数将应用于每个分区。在这个例子,我们定义了一个函数,该函数将返回一个包含每个元素的长度的列表: ```java Function<Iterator<String>, Iterator<Integer>> mapPartitionsFunc = new Function<Iterator<String>, Iterator<Integer>>() { @Override public Iterator<Integer> call(Iterator<String> iterator) throws Exception { ArrayList<Integer> list = new ArrayList<Integer>(); while (iterator.hasNext()) { String s = iterator.next(); list.add(s.length()); } return list.iterator(); } }; ``` 4. 最后,我们将mapPartitions函数应用于JavaRDD对象,并收集结果: ```java JavaRDD<Integer> result = rdd.mapPartitions(mapPartitionsFunc); List<Integer> resultList = result.collect(); for (Integer i : resultList) { System.out.println(i); } ``` 完整的Java代码如下: ```java import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaRDD; import org.apache.spark.api.java.JavaSparkContext; import org.apache.spark.api.java.function.Function; import org.apache.spark.sql.SQLContext; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; public class MapPartitionsExample { public static void main(String[] args) { SparkConf conf = new SparkConf().setAppName("MapPartitionsExample").setMaster("local[*]"); JavaSparkContext sc = new JavaSparkContext(conf); SQLContext sqlContext = new SQLContext(sc); JavaRDD<String> rdd = sc.parallelize(Arrays.asList("apple", "banana", "cherry", "date"), 2); Function<Iterator<String>, Iterator<Integer>> mapPartitionsFunc = new Function<Iterator<String>, Iterator<Integer>>() { @Override public Iterator<Integer> call(Iterator<String> iterator) throws Exception { ArrayList<Integer> list = new ArrayList<Integer>(); while (iterator.hasNext()) { String s = iterator.next(); list.add(s.length()); } return list.iterator(); } }; JavaRDD<Integer> result = rdd.mapPartitions(mapPartitionsFunc); List<Integer> resultList = result.collect(); for (Integer i : resultList) { System.out.println(i); } } } ``` 在这个例子,我们使用mapPartitions方法将每个元素转换成一个整数,然后将结果打印到控制台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值