第 12 篇 java 8 用流分析数据---分区

本文深入探讨Java Stream API中的分区操作,展示了如何利用partitioningBy方法对数据进行高效分类,包括基本的分区、多级分区及优化技巧,旨在帮助开发者更好地理解和应用这一强大特性。
摘要由CSDN通过智能技术生成
/**
 * 分区:
 * 分区是分组的特殊情况:由一个谓词(返回一个布尔值的函数)作为分类函数,它称分区函
 * 数。分区函数返回一个布尔值,这意味着得到的分组Map的键类型是Boolean,于是它最多可以
 * 分为两组——true是一组,false是一组
 */
public class Demo01 {
    public static void main(String[] args) {
        List<Dish> menues = Arrays.asList(new Dish("rice", true, 300, Dish.Type.FISH), new Dish("meate", false, 500, Dish.Type.MEAT), new Dish("dog", true, 30000, Dish.Type.FISH));
//        test01(menues);
//        test02(menues);
        test03(menues);
    }

    /**
     * 如果你是素食者或是请了一位素食的朋友来共
     * 进晚餐,可能会想要把菜单按照素食和非素食分开
     */
    public static void test01(List<Dish> menues) {
        //根据是否是素食主义进行分区
        Map<Boolean, List<Dish>> listMap = menues.stream().collect(Collectors.groupingBy(Dish::isVegetarian));
        //那么通过Map中键为true的值,就可以找出所有的素食菜肴了
        List<Dish> vegetarianPepole = listMap.get(true);
        if (vegetarianPepole != null) {
            System.out.println("素食菜肴是:" + vegetarianPepole);
        } else {
            System.out.println("没有素食菜");
        }
    }

    /**
     * 分区的优势:
     * 分区的好处在于保留了分区函数返回true或false的两套流元素列表。在上一个例子中,要
     * 得到非素食Dish的List,你可以使用两个筛选操作来访问partitionedMenu这个Map中false
     * 键的值:一个利用谓词,一个利用该谓词的非。而且就像你在分组中看到的,partitioningBy
     * 工厂方法有一个重载版本,可以像下面这样传递第二个收集器:
     * 先按照素食主义者进行分区,再在每个区中按照菜的类型进行分组
     */
    public static void test02(List<Dish> menues) {
        Map<Boolean, Map<Dish.Type, List<Dish>>> groupAndPartition = menues.stream().collect(partitioningBy(Dish::isVegetarian, Collectors.groupingBy(Dish::getType)));
        System.out.println(groupAndPartition);

    }

    /**
     * 再举一个例子,你可以重用前面的代码来找到素食和非素
     * 食中热量最高的菜:
     */
    public static void test03(List<Dish> menues) {
        Map<Boolean, Optional<Dish>> dishMap = menues.stream().collect(partitioningBy(Dish::isVegetarian, Collectors.maxBy(Comparator.comparingInt(Dish::getCalories))));
        System.out.println(dishMap.toString());
        //优化
        Map<Boolean, Dish> dishMap2 = menues.stream().collect(partitioningBy(Dish::isVegetarian, Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(Dish::getCalories)), Optional::get)));
        System.out.println(dishMap2.toString());
        //{false=Optional[Dish{name='meate', vegetarian=false, calories=500, type=MEAT}], true=Optional[Dish{name='dog', vegetarian=true, calories=30000, type=FISH}]}
        //{false=Dish{name='meate', vegetarian=false, calories=500, type=MEAT}, true=Dish{name='dog', vegetarian=true, calories=30000, type=FISH}}
    }

    /**
     * 我们在本节开始时说过,你可以把分区看作分组一种特殊情况。 groupingBy 和
     * partitioningBy收集器之间的相似之处并不止于此;你在下一个测验中会看到,还可以按照以往的分组类似的方式进行多级分区;
     * 看看几个简单的例子:
     * 答案:
     * (1) 这是一个有效的多级分区,产生以下二级Map:
     * { false={false=[chicken, prawns, salmon], true=[pork, beef]},
     *  true={false=[rice, season fruit], true=[french fries, pizza]}}
     * (2) 这无法编译,因为partitioningBy需要一个谓词,也就是返回一个布尔值的函数。
     * 方法引用Dish::getType不能用作谓词。
     * (3) 它会计算每个分区中项目的数目,得到以下Map:
     * {false=5, true=4}
     */
    public static void test04(List<Dish> menu) {
        Map<Boolean, Map<Boolean, List<Dish>>> map1 = menu.stream().collect(partitioningBy(Dish::isVegetarian,
                partitioningBy(d -> d.getCalories() > 500)));
        Map<Boolean, Long> map2 = menu.stream().collect(partitioningBy(Dish::isVegetarian,
                counting()));
//        menu.stream().collect(partitioningBy(Dish::isVegetarian,
//                partitioningBy (Dish::getType)));
    }
}

git hub : https://github.com/wangrui0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值