com.feilong.core.util.AggregateUtil Maven / Gradle / Ivy
Show all versions of feilong Show documentation
/*
* 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);
}
/**
* 算术平均值.
*
* 说明:
*
*
* - 返回的 {@link LinkedHashMap},key是
propertyNames
的元素,value是基于这个属性名称获得的值的平均值;key的顺序是依照 propertyNames
元素的顺序
*
*
*
*
* 示例:
*
*
*
* 场景: 求的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
值的总和.
*
* 说明:
*
*
* - 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
*
*
*
* 示例:
*
*
*
* 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
元素的值 ,累计总和.
*
* 说明:
*
*
* - 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
值的总和.
*
* 说明:
*
*
* - 如果通过反射某个元素值是null,则使用默认值0代替,再进行累加
*
*
*
* 示例:
*
*
*
* 场景: 在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
的值出现的次数.
*
* 说明:
*
*
* - 返回的{@link LinkedHashMap},key是
propertyName
对应的值,value是该值出现的次数;
* 顺序是 beanIterable
propertyName
的值的顺序
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
的值出现的次数.
*
* 说明:
*
*
* - 返回的{@link LinkedHashMap},key是
propertyName
对应的值,value是该值出现的次数;
* 顺序是 beanIterable
propertyName
的值的顺序
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
的不同值出现的次数.
*
* 说明:
*
*
* - 返回的{@link LinkedHashMap},key是
propertyName
名字,子map的key是propertyName
对应的值,value是该值出现的次数;
* 顺序是 beanIterable
propertyName
的值的顺序
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
的值出现的次数.
*
* 说明:
*
*
* - 返回的{@link LinkedHashMap},key是
propertyName
名字,子map的key是propertyName
对应的值,value是该值出现的次数;
* 顺序是 beanIterable
propertyName
的值的顺序
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
属性值的转换.
*
* 说明:
*
*
* - 返回的{@link LinkedHashMap},key是
propertyName
名字,子map的key是propertyName
对应的值,value是该值出现的次数;
* 顺序是 beanIterable
propertyName
的值的顺序
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
*
* 返回:
*
*
{
"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
属性值的转换.
*
* 说明:
*
*
* - 返回的{@link LinkedHashMap},key是
propertyName
名字,子map的key是propertyName
对应的值,value是该值出现的次数;
* 顺序是 beanIterable
propertyName
的值的顺序
*
*
*
* 示例:
*
*
*
*
* 场景: 统计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
*
* 返回:
*
*
{
"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