All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.core.util.AggregateUtil Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.feilong.core.util;

import static com.feilong.core.Validator.isNullOrEmpty;
import static com.feilong.core.bean.ConvertUtil.toArray;
import static com.feilong.core.bean.ConvertUtil.toBigDecimal;
import static com.feilong.core.lang.ObjectUtil.defaultIfNull;
import static com.feilong.core.util.CollectionsUtil.size;
import static com.feilong.core.util.MapUtil.newLinkedHashMap;
import static java.math.BigDecimal.ZERO;
import static java.util.Collections.emptyMap;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.collections4.Predicate;
import org.apache.commons.collections4.Transformer;

import com.feilong.core.Validate;
import com.feilong.core.bean.PropertyUtil;
import com.feilong.core.lang.NumberUtil;

/**
 * 专门用来统计数据的工具类.
 * 
 * 

* 类似于sql里面的 统计函数 (Aggregate functions) *

* * @author feilong * @see "java.util.stream.Collectors" * @since 1.8.0 */ //Aggregate Functions @SuppressWarnings("squid:S1192") //String literals should not be duplicated public final class AggregateUtil{ /** Don't let anyone instantiate this class. */ private AggregateUtil(){ //AssertionError不是必须的. 但它可以避免不小心在类的内部调用构造器. 保证该类在任何情况下都不会被实例化. //see 《Effective Java》 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } //-------------------------avg-------------------------------------- /** * 算术平均值. * *

示例:

*
* *

* 场景: 求的User list 里面 id属性 的平均值 *

* *
     * List{@code } list = new ArrayList{@code <>}();
     * list.add(new User(2L));
     * list.add(new User(5L));
     * list.add(new User(5L));
     * AggregateUtil.avg(list, "id", 2)
     * 
* * 返回: 4.00 *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param scale * 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况) * @return 如果 beanIterable 是null或者empty,返回 null
* 如果 propertyName 是null,抛出 {@link NullPointerException}
* 如果 propertyName 是blank,抛出 {@link IllegalArgumentException}
* @see #sum(Iterable, String...) */ public static BigDecimal avg(Iterable beanIterable,String propertyName,int scale){ Validate.notBlank(propertyName, "propertyName can't be blank!"); return isNullOrEmpty(beanIterable) ? null : avg(beanIterable, toArray(propertyName), scale).get(propertyName); } /** * 算术平均值. * *

说明:

*
*
    *
  1. 返回的 {@link LinkedHashMap},key是 propertyNames的元素,value是基于这个属性名称获得的值的平均值;key的顺序是依照 propertyNames元素的顺序 *
  2. *
*
* *

示例:

*
* *

* 场景: 求的User list 里面 age 以及id属性 的平均值 *

* *
     * User user1 = new User(2L);
     * user1.setAge(18);
     * 
     * User user2 = new User(3L);
     * user2.setAge(30);
     * 
     * List{@code } list = toList(user1, user2);
     * Map{@code } map = AggregateUtil.avg(list, ConvertUtil.toArray("id", "age"), 2);
     * LOGGER.info(JsonUtil.format(map));
     * 
* * 返回: * *
     * {
     * "id": 2.5,
     * "age": 24
     * }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param scale * 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况) * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果propertyNames 是null 抛出 {@link NullPointerException} 异常
* 如果propertyNames 有元素是null 抛出 {@link IllegalArgumentException}
* @see #sum(Iterable, String...) */ public static Map avg(Iterable beanIterable,String[] propertyNames,int scale){ if (isNullOrEmpty(beanIterable)){ return emptyMap(); } Map sumMap = sum(beanIterable, propertyNames);//先求和 int size = size(beanIterable); Map map = newLinkedHashMap(size); for (Map.Entry entry : sumMap.entrySet()){ map.put(entry.getKey(), NumberUtil.getDivideValue(toBigDecimal(entry.getValue()), size, scale)); } return map; } //--------------------------sum------------------------------------- /** * 总和,计算集合对象beanIterable 内指定的属性名 propertyName 值的总和. * *

说明:

*
*
    *
  1. 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
  2. *
*
* *

示例:

*
* *
     * List{@code } list = new ArrayList{@code <>}();
     * list.add(new User(2L));
     * list.add(new User(5L));
     * list.add(new User(5L));
     * 
     * LOGGER.info("" + AggregateUtil.sum(list, "id"));
     * 
* * 返回: 12 * *
* *

说明:

* *
* *

* 当你需要写这样的代码的时候, *

* *
     * 
     * protected Integer getCookieShoppingCartLinesQty(List{@code } cartLineList){
     *     Integer qty = 0;
     *     //获取cookie中的购物车行集合
     *     if ({@code null != cartLineList && cartLineList.size() > 0}){
     *         for (Iterator iterator = cartLineList.iterator(); iterator.hasNext();){
     *             CookieShoppingCartLine cookieShoppingCartLine = (CookieShoppingCartLine) iterator.next();
     *             qty += cookieShoppingCartLine.getQuantity();
     *         }
     *     }
     *     return qty;
     * }
     * 
* *

* 你可以写成: *

* *
     * 
     * protected Integer getCookieShoppingCartLinesQty(List{@code } cartLineList){
     *     return isNullOrEmpty(cartLineList) ? 0 : AggregateUtil.sum(cartLineList, "quantity").intValue();
     * }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @return 如果 beanIterable 是null或者 empty,返回 null
* 如果 propertyName 是null,抛出 {@link NullPointerException}
* 如果 propertyName 是blank,抛出 {@link IllegalArgumentException} * @see #sum(Iterable, String...) */ public static BigDecimal sum(Iterable beanIterable,String propertyName){ Validate.notBlank(propertyName, "propertyName can't be blank!"); return sum(beanIterable, propertyName, null); } /** * 迭代beanIterable,提取 符合 includePredicate的元素的指定 propertyName 元素的值 ,累计总和. * *

说明:

*
*
    *
  1. 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list(条件是 id {@code >}10),id属性值的总和 *

* *
     * 
     * List{@code } list = new ArrayList{@code <>}();
     * list.add(new User(2L));
     * list.add(new User(50L));
     * list.add(new User(50L));
     * 
     * AggregateUtil.sum(list, "id", new Predicate{@code }(){
     * 
     *     {@code @Override}
     *     public boolean evaluate(User user){
     *         return user.getId() {@code >} 10L;
     *     }
     * });
     * 
     * 
* *

* 返回: new BigDecimal(100L) *

* *

* 当然这段代码,你还可以优化成: *

* *
     * Predicate{@code } predicate = new ComparatorPredicate{@code }(10L, ComparatorUtils.{@code } naturalComparator(), Criterion.LESS);
     * BigDecimal sum = AggregateUtil.sum(list, "id", new BeanPredicate{@code }("id", predicate));
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param includePredicate * the include predicate * @return 如果 beanIterable 是null或者 empty,返回 null
* 如果 propertyName 是null,抛出 {@link NullPointerException}
* 如果 propertyName 是blank,抛出 {@link IllegalArgumentException}
* 如果 includePredicate 是null,那么迭代所有的元素
* 如果beanIterable没有符合 includePredicate的元素,返回 null * @see #sum(Iterable, String[], Predicate) */ public static BigDecimal sum(Iterable beanIterable,String propertyName,Predicate includePredicate){ Validate.notBlank(propertyName, "propertyName can't be null/empty!"); return sum(beanIterable, toArray(propertyName), includePredicate).get(propertyName); } /** * 求和,分别计算集合对象beanIterable 内指定的不同属性名 propertyNames 值的总和. * *

说明:

*
*
    *
  1. 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
  2. *
*
* *

示例:

*
* *

* 场景: 在user list 中,分别统计 id属性以及age属性值总和 *

* *
     * User user1 = new User(2L);
     * user1.setAge(18);
     * 
     * User user2 = new User(3L);
     * user2.setAge(30);
     * 
     * Map{@code } map = AggregateUtil.sum(toList(user1, user2), "id", "age");
     * LOGGER.info(JsonUtil.format(map));
     * 
* * 返回: * *
     * {
     * "id": 5,
     * "age": 48
     * }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果propertyNames 是null 抛出 {@link NullPointerException} 异常
* 如果propertyNames 有元素是null 抛出 {@link IllegalArgumentException}
* @see #sum(Iterable, String[], Predicate) */ public static Map sum(Iterable beanIterable,String...propertyNames){ return sum(beanIterable, propertyNames, null); } /** * 迭代beanIterable,提取符合 includePredicate的元素的指定 propertyNames 元素的值 ,累计总和. * *

示例:

* *
* *
     * User user1 = new User(10L);
     * user1.setName("刘备");
     * user1.setAge(50);
     * 
     * User user2 = new User(20L);
     * user1.setName("关羽");
     * user2.setAge(50);
     * 
     * User user3 = new User(100L);
     * user3.setName("张飞");
     * user3.setAge(100);
     * 
     * List{@code } list = toList(user1, user2, user3);
     * Map{@code } map = AggregateUtil.sum(list, ConvertUtil.toArray("id", "age"), new Predicate{@code }(){
     * 
     *     {@code @Override}
     *     public boolean evaluate(User user){
     *         return !"张飞".equals(user.getName());
     *     }
     * });
     * LOGGER.debug(JsonUtil.format(map));
     * 
     * 
* * 返回: * *
     * {
     * "id": 30,
     * "age": 100
     * }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param includePredicate * the include predicate * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
* 如果 includePredicate 是null,那么迭代所有的元素
* 如果beanIterable没有符合 includePredicate的元素,返回 new LinkedHashMap * @throws NullPointerException * 如果propertyNames 是null * @throws IllegalArgumentException * 果propertyNames 有元素 是null
*/ public static Map sum(Iterable beanIterable,String[] propertyNames,Predicate includePredicate){ if (isNullOrEmpty(beanIterable)){ return emptyMap(); } Validate.noNullElements(propertyNames, "propertyNames can't be null/empty!"); Map sumMap = newLinkedHashMap(size(beanIterable)); for (O obj : beanIterable){ if (null != includePredicate && !includePredicate.evaluate(obj)){ continue; } for (String propertyName : propertyNames){ //如果通过反射某个元素值是null,则使用默认值0 代替 BigDecimal addValue = NumberUtil.getAddValue( defaultIfNull(sumMap.get(propertyName), 0), defaultIfNull(PropertyUtil. getProperty(obj, propertyName), 0)); sumMap.put(propertyName, addValue); } } return sumMap; } //--------------------------------------------------------------- /** * 迭代beanIterable,取元素 keyPropertyName 的值为 key ,累计 sumPropertyName 属性值 为 value,返回 map. * *

示例:

* *
* *

* 统计 user list 按照姓名分组, 累加每个人的 age 总和 *

* *
     * List{@code } list = toList(//
     *                 new User("张飞", 20),
     *                 new User("关羽", 20),
     *                 new User("刘备", 20),
     *                 new User("刘备", 20));
     * 
     * Map{@code } map = AggregateUtil.groupSum(list, "name", "age");
     * 
     * 
* * assertThat: * *
     * assertThat(
     *                 map,
     *                 allOf(//
     *                                 hasEntry("刘备", toBigDecimal(40)),
     *                                 hasEntry("张飞", toBigDecimal(20)),
     *                                 hasEntry("关羽", toBigDecimal(20))));
     * 
* *
* * @param * bean对象 或者可以被提取属性的对象 * @param * keyPropertyName对应的属性值 * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param keyPropertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param sumPropertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
* 如果 keyPropertyName 是null,抛出 {@link NullPointerException}
* 如果 keyPropertyName 是blank,抛出 {@link IllegalArgumentException}
* 如果 sumPropertyName 是null,抛出 {@link NullPointerException}
* 如果 sumPropertyName 是blank,抛出 {@link IllegalArgumentException}
* @since 1.13.2 */ public static Map groupSum(Iterable beanIterable,String keyPropertyName,String sumPropertyName){ return groupSum(beanIterable, keyPropertyName, sumPropertyName, null); } /** * 迭代beanIterable,提取符合 includePredicate的元素,取元素 keyPropertyName 的值为 key ,累计 * sumPropertyName 属性值 为 value,返回 map. * *

* 统计 user list 所有 age 小于等于30的, 按照姓名分组, 累加每个人的 age 总和 *

* *
     * 
     * Predicate{@code } comparatorPredicate = BeanPredicateUtil.comparatorPredicate("age", 30, Criterion.GREATER_OR_EQUAL);
     * 
     * List{@code } list = toList(//
     *                 new User("张飞", 20),
     *                 new User("关羽", 20),
     *                 new User("刘备", 20),
     *                 new User("刘备", 50),
     *                 new User("刘备", 20));
     * 
     * Map{@code } map = AggregateUtil.groupSum(list, "name", "age",comparatorPredicate);
     * 
     * 
* * assertThat: * *
     * assertThat(
     *                 map,
     *                 allOf(//
     *                                 hasEntry("刘备", toBigDecimal(40)),
     *                                 hasEntry("张飞", toBigDecimal(20)),
     *                                 hasEntry("关羽", toBigDecimal(20))));
     * 
* * @param * the generic type * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param keyPropertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param sumPropertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param includePredicate * the include predicate * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
* 如果 includePredicate 是null,那么迭代所有的元素
* 如果 beanIterable没有符合 includePredicate的元素,返回 new LinkedHashMap * * 如果 keyPropertyName 是null,抛出 {@link NullPointerException}
* 如果 keyPropertyName 是blank,抛出 {@link IllegalArgumentException}
* 如果 sumPropertyName 是null,抛出 {@link NullPointerException}
* 如果 sumPropertyName 是blank,抛出 {@link IllegalArgumentException}
* @since 1.13.2 */ public static Map groupSum( Iterable beanIterable, String keyPropertyName, String sumPropertyName, Predicate includePredicate){ if (isNullOrEmpty(beanIterable)){ return emptyMap(); } //--------------------------------------------------------------- Validate.notBlank(keyPropertyName, "keyPropertyName can't be null/empty!"); Validate.notBlank(sumPropertyName, "sumPropertyName can't be null/empty!"); Map map = newLinkedHashMap(); for (O obj : beanIterable){ if (null != includePredicate && !includePredicate.evaluate(obj)){ continue; } T keyPropertyValue = PropertyUtil. getProperty(obj, keyPropertyName); BigDecimal value = toBigDecimal(defaultIfNull(PropertyUtil. getProperty(obj, sumPropertyName), ZERO)); MapUtil.putSumValue(map, keyPropertyValue, value); } return map; } //--------------------------------------------------------------- /** * 循环 beanIterable,统计 propertyName 的值出现的次数. * *

说明:

*
*
    *
  1. 返回的{@link LinkedHashMap},key是propertyName对应的值,value是该值出现的次数;
    * 顺序是 beanIterable propertyName的值的顺序
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list,属性名字是name 的值的数量 *

* *
     * List{@code } list = new ArrayList{@code <>}();
     * list.add(new User("张飞"));
     * list.add(new User("关羽"));
     * list.add(new User("刘备"));
     * list.add(new User("刘备"));
     * 
     * Map{@code } map = AggregateUtil.groupCount(list, "name");
     * LOGGER.info(JsonUtil.format(map));
     * 
* * 返回: * *
     * {
     * "张飞": 1,
     * "关羽": 1,
     * "刘备": 2
     * }
     * 
* *
* * @param * the generic type * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果 propertyName 是null,抛出 {@link NullPointerException}
* 如果 propertyName 是blank,抛出 {@link IllegalArgumentException} * @see #groupCount(Iterable , String, Predicate) * @see com.feilong.lib.collection4.CollectionUtils#getCardinalityMap(Iterable) */ public static Map groupCount(Iterable beanIterable,String propertyName){ return groupCount(beanIterable, propertyName, null); } /** * 循环 beanIterable,只选择符合 includePredicate的对象,统计 propertyName的值出现的次数. * *

说明:

*
*
    *
  1. 返回的{@link LinkedHashMap},key是propertyName对应的值,value是该值出现的次数;
    * 顺序是 beanIterable propertyName的值的顺序
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list(条件是 age {@code >} 30 的user),name属性值的数量 *

* *
     * List{@code } list = new ArrayList{@code <>}();
     * list.add(new User("张飞", 20));
     * list.add(new User("关羽", 30));
     * list.add(new User("刘备", 40));
     * list.add(new User("赵云", 50));
     * 
     * Map{@code } map = AggregateUtil.groupCount(list, "name", new Predicate{@code }(){
     *     {@code @Override}
     *     public boolean evaluate(User user){
     *         return user.getAge() {@code >} 30;
     *     }
     * });
     * LOGGER.debug(JsonUtil.format(map));
     * 
     * 
* * 返回: * *
     * {
     * "刘备": 1,
     * "赵云": 1
     * }
     * 
     * 
* *
* * @param * the generic type * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyName * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param includePredicate * 只选择 符合 includePredicate的对象,如果是null 则统计集合中全部的元素 * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果 propertyName 是null,抛出 {@link NullPointerException}
* 如果 propertyName 是blank,抛出 {@link IllegalArgumentException}
* 如果 includePredicate 是null,则统计集合中全部的元素
* @see com.feilong.lib.collection4.CollectionUtils#getCardinalityMap(Iterable) */ public static Map groupCount(Iterable beanIterable,String propertyName,Predicate includePredicate){ if (isNullOrEmpty(beanIterable)){ return emptyMap(); } Validate.notBlank(propertyName, "propertyName can't be null/empty!"); Map map = newLinkedHashMap(); for (O obj : beanIterable){ if (null != includePredicate && !includePredicate.evaluate(obj)){ continue; } MapUtil.putSumValue(map, PropertyUtil. getProperty(obj, propertyName), 1); } return map; } //--------------------------------------------------------------- /** * 循环 beanIterable,统计不同 propertyNames的不同值出现的次数. * *

说明:

*
*
    *
  1. 返回的{@link LinkedHashMap},key是propertyName名字,子map的key是propertyName对应的值,value是该值出现的次数;
    * 顺序是 beanIterable propertyName的值的顺序
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list,属性名字是name 的值的数量 以及age值的数量 *

* *
     * List{@code } list = toList(//
     *                 new User("张飞", 20),
     *                 new User("关羽", 30),
     *                 new User("赵云", 50),
     *                 new User("刘备", 40),
     *                 new User("刘备", 30),
     *                 new User("赵云", 50));
     * 
     * Map{@code >} map = AggregateUtil.groupCount(list, toArray("name", "age"));
     * 
     * LOGGER.debug(JsonUtil.format(map));
     * 
* * 返回: * *
     *     {
     *         "age":         {
     *             "20": 1,
     *             "30": 2,
     *             "50": 2,
     *             "40": 1
     *         },
     *         "name":         {
     *             "张飞": 1,
     *             "关羽": 1,
     *             "赵云": 2,
     *             "刘备": 2
     *         }
     *     }
     * 
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果 propertyNames 是null,抛出 {@link NullPointerException}
* 如果 propertyNames 是empty,抛出 {@link IllegalArgumentException}
* 如果 循环的propertyName 是null,抛出 {@link NullPointerException}
* 如果 循环的propertyName 是empty或者blank,抛出 {@link IllegalArgumentException}
* @see com.feilong.lib.collection4.CollectionUtils#getCardinalityMap(Iterable) * @since 1.10.6 * @since 1.10.7 change param type from {@code String[] propertyNames} to {@code String...propertyNames}
* change return type from {@code Map>} to {@code Map>} */ public static Map> groupCount(Iterable beanIterable,String...propertyNames){ return groupCount(beanIterable, propertyNames, (Predicate) null); } /** * 循环 beanIterable,只选择符合 includePredicate的对象,分别统计 propertyNames的值出现的次数. * *

说明:

*
*
    *
  1. 返回的{@link LinkedHashMap},key是propertyName名字,子map的key是propertyName对应的值,value是该值出现的次数;
    * 顺序是 beanIterable propertyName的值的顺序
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list(条件是 age {@code >} 30 的user),name属性值的数量以及age 的数量 *

* *
     * List{@code } list = toList(//
     *                 new User("张飞", 20),
     *                 new User("关羽", 30),
     *                 new User("赵云", 50),
     *                 new User("刘备", 40),
     *                 new User("刘备", 30),
     *                 new User("赵云", 50));
     * 
     * Predicate{@code } comparatorPredicate = BeanPredicateUtil.comparatorPredicate("age", 30, Criterion.LESS);
     * Map{@code >} map = AggregateUtil.groupCount(list, toArray("name", "age"), comparatorPredicate);
     * 
     * LOGGER.debug(JsonUtil.format(map));
     * 
* * 返回: * *
     *     {
     *         "age":         {
     *             "50": 2,
     *             "40": 1
     *         },
     *         "name":         {
     *             "赵云": 2,
     *             "刘备": 1
     *         }
     *     }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param includePredicate * 只选择 符合 includePredicate的对象,如果是null 则统计集合中全部的元素 * @return 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果 propertyNames 是null,抛出 {@link NullPointerException}
* 如果 propertyNames 是empty,抛出 {@link IllegalArgumentException}
* 如果 循环的propertyName 是null,抛出 {@link NullPointerException}
* 如果 循环的propertyName 是empty或者blank,抛出 {@link IllegalArgumentException}
* 如果 includePredicate 是null,则统计集合中全部的元素
* @see com.feilong.lib.collection4.CollectionUtils#getCardinalityMap(Iterable) * @since 1.10.6 * @since 1.10.7 change return type from {@code Map>} to {@code Map>} */ public static Map> groupCount( Iterable beanIterable, String[] propertyNames, Predicate includePredicate){ return groupCount(beanIterable, propertyNames, null, includePredicate); } /** * 循环 beanIterable,分别统计 propertyNames的值出现的次数,统计的时候支持使用 * propertyValueAndTransformerMap 属性值的转换. * *

说明:

*
*
    *
  1. 返回的{@link LinkedHashMap},key是propertyName名字,子map的key是propertyName对应的值,value是该值出现的次数;
    * 顺序是 beanIterable propertyName的值的顺序
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list,name属性值的数量以及age 的数量,并且 age以范围区间统计 *

* *
    List{@code } list = toList(//
                        new User("张飞", 20),
                        new User("关羽", 30),
                        new User("刘备", 32),
                        new User("刘备", 40),
                        new User("赵云", 51),
                        new User("赵云", 50));
    
        Transformer{@code } transformer = new Transformer{@code }(){
    
            public String transform(Integer input){
                if ({@code input >= 50}){
                    return {@code ">=50"};
                }
                if ({@code input >= 30 && input < 50}){
                    return {@code ">=30&&<50"};
                }
                if ({@code input >= 20 && input < 30}){
                    return {@code ">=20&&<30"};
                }               
                throw new UnsupportedOperationException("value not support!");
            }
    
        };
    
        //---------------------------------------------------------------
        Map{@code >} propertyValueAndTransformerMap = toMap("age", (Transformer{@code }) transformer);
    
        //---------------------------------------------------------------
    
        Map{@code >} map = AggregateUtil
                        .groupCount(list, toArray("name", "age"), propertyValueAndTransformerMap);
    
        LOGGER.debug(JsonUtil.format(map));
     * 
* * 返回: * *
    {
        "name":         {
            "张飞": 1,
            "关羽": 1,
            "刘备": 2,
            "赵云": 2
        },
        "age":         {
            {@code ">=20&&<30"}: 1,
            {@code ">=30&&<50"}: 3,
            {@code ">=50"}: 2
        }
    }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param propertyValueAndTransformerMap * the property name value converter map * @return 如果 propertyValueAndTransformerMap 是null或者empty,方法等于 {@link #groupCount(Iterable, String[], Predicate)}
* 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果 propertyNames 是null,抛出 {@link NullPointerException}
* 如果 propertyNames 是empty,抛出 {@link IllegalArgumentException}
* 如果 循环的propertyName 是null,抛出 {@link NullPointerException}
* 如果 循环的propertyName 是empty或者blank,抛出 {@link IllegalArgumentException}
* @see com.feilong.lib.collection4.CollectionUtils#getCardinalityMap(Iterable) * @since 1.10.7 */ public static Map> groupCount( Iterable beanIterable, String[] propertyNames, Map> propertyValueAndTransformerMap){ return groupCount(beanIterable, propertyNames, propertyValueAndTransformerMap, null); } /** * 循环 beanIterable,只选择符合 includePredicate的对象,分别统计 propertyNames的值出现的次数,统计的时候支持使用 * propertyValueAndTransformerMap 属性值的转换. * *

说明:

*
*
    *
  1. 返回的{@link LinkedHashMap},key是propertyName名字,子map的key是propertyName对应的值,value是该值出现的次数;
    * 顺序是 beanIterable propertyName的值的顺序
  2. *
*
* *

示例:

* *
* *

* 场景: 统计user list(条件是 age {@code >} 30 的user),name属性值的数量以及age 的数量,并且 age以范围区间统计 *

* *
    List{@code } list = toList(//
                        new User("张飞", 20),
                        new User("关羽", 30),
                        new User("刘备", 32),
                        new User("刘备", 40),
                        new User("赵云", 51),
                        new User("赵云", 50));
    
        Transformer{@code } transformer = new Transformer{@code }(){
    
            public String transform(Integer input){
                if ({@code input >= 50}){
                    return {@code ">=50"};
                }
                if ({@code input >= 30 && input < 50}){
                    return {@code ">=30&&<50"};
                }
                throw new UnsupportedOperationException("value not support!");
            }
    
        };
    
        //---------------------------------------------------------------
        Map{@code >} propertyValueAndTransformerMap = toMap("age", (Transformer{@code }) transformer);
    
        Predicate{@code } comparatorPredicate = BeanPredicateUtil.comparatorPredicate("age", 30, Criterion.LESS);
    
        //---------------------------------------------------------------
    
        Map{@code >} map = AggregateUtil
                        .groupCount(list, toArray("name", "age"), propertyValueAndTransformerMap, comparatorPredicate);
    
        LOGGER.debug(JsonUtil.format(map));
     * 
* * 返回: * *
    {
        "name":         {
            "刘备": 2,
            "赵云": 2
        },
        "age":         {
            {@code ">=30&&<50"}: 2,
            {@code ">=50"}: 2
        }
    }
     * 
* *
* * @param * the generic type * @param beanIterable * bean Iterable,诸如List{@code },Set{@code }等 * @param propertyNames * 泛型O对象指定的属性名称,Possibly indexed and/or nested name of the property to be modified,参见 * propertyName * @param propertyValueAndTransformerMap * the property name value converter map * @param includePredicate * 只选择 符合 includePredicate的对象,如果是null 则统计集合中全部的元素 * @return 如果 propertyValueAndTransformerMap 是null或者empty,方法等于 {@link #groupCount(Iterable, String[], Predicate)}
* 如果 beanIterable 是null或者empty,返回 {@link Collections#emptyMap()}
* 如果 propertyNames 是null,抛出 {@link NullPointerException}
* 如果 propertyNames 是empty,抛出 {@link IllegalArgumentException}
* 如果 循环的propertyName 是null,抛出 {@link NullPointerException}
* 如果 循环的propertyName 是empty或者blank,抛出 {@link IllegalArgumentException}
* 如果 includePredicate 是null,则统计集合中全部的元素
* @see com.feilong.lib.collection4.CollectionUtils#getCardinalityMap(Iterable) * @since 1.10.7 */ public static Map> groupCount( Iterable beanIterable, String[] propertyNames, Map> propertyValueAndTransformerMap, Predicate includePredicate){ if (isNullOrEmpty(beanIterable)){ return emptyMap(); } Validate.notEmpty(propertyNames, "propertyNames can't be null/empty!"); for (String propertyName : propertyNames){ Validate.notBlank(propertyName, "propertyName can't be blank!"); } //--------------------------------------------------------------- Map> resultMap = newLinkedHashMap(propertyNames.length); for (O bean : beanIterable){ if (null != includePredicate && !includePredicate.evaluate(bean)){ continue; } handlerForeachPropertyNames(propertyNames, propertyValueAndTransformerMap, resultMap, bean); } return resultMap; } //--------------------------------------------------------------- /** * Handler foreach property names. * * @param * the generic type * @param propertyNames * the property names * @param propertyNameValueConverterMap * the property name value converter map * @param resultMap * the result map * @param bean * the bean * @since 1.10.7 */ private static void handlerForeachPropertyNames( String[] propertyNames, Map> propertyNameValueConverterMap, Map> resultMap, O bean){ for (String propertyName : propertyNames){ //取map,如果没有构造一个 Map propertyNameGroupCountMap = defaultIfNull( resultMap.get(propertyName), new LinkedHashMap()); Object value = convertValue(bean, propertyName, propertyNameValueConverterMap); MapUtil.putSumValue(propertyNameGroupCountMap, value, 1); //--------------------------------------------------------------- resultMap.put(propertyName, propertyNameGroupCountMap); } } /** * Convert value. * * @param * the generic type * @param * the generic type * @param obj * the obj * @param propertyName * the property name * @param propertyValueAndTransformerMap * the property name value converter map * @return the string * @since 1.10.7 */ private static Object convertValue( O obj, String propertyName, Map> propertyValueAndTransformerMap){ T value = PropertyUtil. getProperty(obj, propertyName); if (isNullOrEmpty(propertyValueAndTransformerMap)){ return value; } //--------------------------------------------------------------- Transformer transformer = propertyValueAndTransformerMap.get(propertyName); if (null == transformer){ return value; } //--------------------------------------------------------------- return transformer.transform(value); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy