[Java Collection]List分组之简单应用.
来源:互联网 发布:python 图片相似度 库 编辑:程序博客网 时间:2024/04/28 16:24
前言
今天有一个新需求, 是对一个List进行分组, 于是便百度到一些可用的代码以及我们项目使用的一些tools, 在这里总结下方便以后查阅.
一: 需求
现在我们一个数据库表t_series_value_rate存储的是每个汽车对应的保值率. 其中一个车系id可以对应多条数据.表内容部分截取如下:
其中series_id是车系id, car_year代表这个车的年限. 比如说车系id为1的车1年的保值率为81.5%, 2年的保值率为73.7%.
那么现在我需要传递过来一个series_id list去查询出相应的数据, 我们是对数据库表t_series_value_rate查询所有做了缓存的, 如果我们对传入的series_id list进行遍历的话势必会很慢. 所以如果能够根据series_id进行分组的话, 那么效率就会高的多.
二: 代码示例
对外暴漏的API接口, 方便别的项目调用:
public List<HashMap<Long, List<SeriesValueRateDTO>>> listSeriesValueRates(List<Long> seriesIds) throws Exception { ApiResponse response = httpGet("/api/server/series-value-rates/list-series-value-rates.htm?seriesIds=" + Joiner.on(",").skipNulls().join(seriesIds)); return JSON.parseObject(response.getJsonObject().get("data").toString(), new TypeReference<List<HashMap<Long, List<SeriesValueRateDTO>>>>(){});}
这里我们传入的是一个车系id集合.
然后继续往下调用:
public List<SeriesValueRateDTO> listSeriesValueRate(final long seriesId) { String key = "listSeriesValueRate" + seriesId; return managerService.get(key, new Callable<List<SeriesValueRateDTO>>() { @Override public List<SeriesValueRateDTO> call() throws Exception { Map<Long, List<SeriesValueRateDTO>> valueRateDTOs = listAllSeriesValueRate(); List<SeriesValueRateDTO> dtos = valueRateDTOs.get(seriesId); return dtos; } }, CommonConstants.ExpiredTime.ONE_DAY);}
这里使用了DCache去缓存不同的seriesId对应的数据, 接下来再看看查询所有车系保值率数据(listAllSeriesValueRate()):
private LoadingCache<String, Map<Long, List<SeriesValueRateDTO>>> cache = CacheBuilder.newBuilder() .expireAfterWrite(12,TimeUnit.HOURS) .build(new CacheLoader<String, Map<Long, List<SeriesValueRateDTO>>>() { @Override public Map<Long, List<SeriesValueRateDTO>> load(String k) { List<SeriesValueRateDTO> valueRateDTOs = Lists.newArrayList(); List<SeriesValueRateEntity> entities = seriesValueRateEntityDao.findAll(SeriesValueRateEntity.Fields.seriesId.notNull()); for (SeriesValueRateEntity entity : entities) { SeriesValueRateDTO dto = new SeriesValueRateDTO(); dto.setSeriesId(entity.getSeriesId()); dto.setCarYear(entity.getCarYear()); dto.setValueRate(entity.getValueRate()); valueRateDTOs.add(dto); } //按照seriesId进行分组 Map<Long, List<SeriesValueRateDTO>> map = Maps.newHashMap(); //第17行 GroupUtils.listGroup2Map(valueRateDTOs, map, SeriesValueRateDTO.class, "getSeriesId");//第18行 return map; }});
这里使用了GuavaCache去缓存所有的车系保值率数据, 然后这里使用了GroupUtils去进行分组, 分组是按照"getSeriesId"来获取seriesId进行分组. 我们来查看下分组前的数据结构(代码中第17行处查看debug数据):
然后再看看分组后的数据结构(运行完第18行数据结果):
很显然, 数据已经进行了分组, 最后看看我们是如何高效率的通过传入的seriesIds取值的:
public List<HashMap<Long, List<SeriesValueRateDTO>>> listSeriesValueRates() { WebContext context = WebContext.get(); List<Long> ids =context.getRequiredLongList("seriesIds"); List<HashMap<Long, List<SeriesValueRateDTO>>> seriesValueRateDTOs = Lists.newArrayList(); for (long seriesId : ids) { HashMap<Long, List<SeriesValueRateDTO>> map = Maps.newHashMap(); List<SeriesValueRateDTO> dtos = seriesValueRateEntityService.listSeriesValueRate(seriesId); map.put(seriesId, dtos); seriesValueRateDTOs.add(map); } return seriesValueRateDTOs;}public List<SeriesValueRateDTO> listSeriesValueRate(final long seriesId) { String key = "listSeriesValueRate" + seriesId; return managerService.get(key, new Callable<List<SeriesValueRateDTO>>() { @Override public List<SeriesValueRateDTO> call() throws Exception { Map<Long, List<SeriesValueRateDTO>> valueRateDTOs = listAllSeriesValueRate(); List<SeriesValueRateDTO> dtos = valueRateDTOs.get(seriesId); return dtos; } }, CommonConstants.ExpiredTime.ONE_DAY);}
这里再放上SeriesValueRateDTO:
public class SeriesValueRateDTO { /** * 车系id */ private long seriesId; /** * 保值率 */ private Double valueRate; /** * 车辆年限 */ private int carYear; public long getSeriesId() { return seriesId; } public void setSeriesId(long seriesId) { this.seriesId = seriesId; } public Double getValueRate() { return valueRate; } public void setValueRate(Double valueRate) { this.valueRate = valueRate; } public int getCarYear() { return carYear; } public void setCarYear(int carYear) { this.carYear = carYear; }}
三: 分组工具类GroupUtils
这里直接铺上代码, 其实也很简单, 具体使用规则请参考上面.
public class GroupUtils { private static final Logger LOGGER = LoggerFactory.getLogger(GroupUtils.class); /** * 分组依赖接口 */ public interface GroupBy<T> { T groupby(Object obj); } /** * * @param colls * @param gb * @return */ public static final <T extends Comparable<T>, D> Map<T, List<D>> group(Collection<D> colls, GroupBy<T> gb) { if (colls == null || colls.isEmpty()) { LOGGER.info("分组集合不能为空!"); return null; } if (gb == null) { LOGGER.info("分组依赖接口不能为Null!"); return null; } Iterator<D> iter = colls.iterator(); Map<T, List<D>> map = new HashMap<T, List<D>>(); while (iter.hasNext()) { D d = iter.next(); T t = gb.groupby(d); if (map.containsKey(t)) { map.get(t).add(d); } else { List<D> list = new ArrayList<D>(); list.add(d); map.put(t, list); } } return map; } /** * 将List<V>按照V的methodName方法返回值(返回值必须为K类型)分组,合入到Map<K, List<V>>中<br> * 要保证入参的method必须为V的某一个有返回值的方法,并且该返回值必须为K类型 * * @param list * 待分组的列表 * @param map * 存放分组后的map * @param clazz * 泛型V的类型 * @param methodName * 方法名 */ public static <K, V> void listGroup2Map(List<V> list, Map<K, List<V>> map, Class<V> clazz, String methodName) { // 入参非法行校验 if (null == list || null == map || null == clazz) { LOGGER.info("CommonUtils.listGroup2Map 入参错误,list:" + list + " ;map:" + map + " ;clazz:" + clazz + " ;methodName:" + methodName); return; } // 获取方法 Method method = getMethodByName(clazz, methodName); // 非空判断 if (null == method) { return; } // 正式分组 listGroup2Map(list, map, method); } /** * 根据类和方法名,获取方法对象 * * @param clazz * @param methodName * @return */ public static Method getMethodByName(Class<?> clazz, String methodName) { Method method = null; // 入参不能为空 if (null == clazz) { LOGGER.info("GroupUtils.getMethodByName 入参错误,clazz:" + clazz + " ;methodName:" + methodName); return method; } try { method = clazz.getDeclaredMethod(methodName); } catch (Exception e) { LOGGER.info("类获取方法失败!"); } return method; } /** * 将List<V>按照V的某个方法返回值(返回值必须为K类型)分组,合入到Map<K, List<V>>中<br> * 要保证入参的method必须为V的某一个有返回值的方法,并且该返回值必须为K类型 * * @param list * 待分组的列表 * @param map * 存放分组后的map * @param method * 方法 */ @SuppressWarnings("unchecked") public static <K, V> void listGroup2Map(List<V> list, Map<K, List<V>> map, Method method) { // 入参非法行校验 if (null == list || null == map || null == method) { LOGGER.info("GroupUtils.listGroup2Map 入参错误,list:" + list + " ;map:" + map + " ;method:" + method); return; } try { // 开始分组 Object key; List<V> listTmp; for (V val : list) { key = method.invoke(val); listTmp = map.get(key); if (null == listTmp) { listTmp = new ArrayList<V>(); map.put((K) key, listTmp); } listTmp.add(val); } } catch (Exception e) { LOGGER.info("分组失败!"); } }}
最后大家可以根据自己的需求来选择改造或使用. 回头发现项目中能学到的东西很多, 记录下来希望以后能够多看看. 2016/12/06 http://www.cnblogs.com/wang-meng/
- [Java Collection]List分组之简单应用.
- 【java】Collection分组
- Java之Collection接口之List
- Java-集合框架Collection之List(一)
- Java-集合框架Collection之List(二)
- java集合之Collection---set/map/list
- Java集合类系列2--Collection之List和Set简单介绍
- Collection 之List
- Collection集合之List
- 集合Collection之List
- 集合之Collection、List
- Collection之List集合
- Java Collection Framework : List
- java基础--Collection List
- java-Collection(List、Set)
- 【转载】java List分组和排序处理 Map 应用
- Java List 分组
- java List分组
- [转载]从MyEclipse到IntelliJ IDEA-让你摆脱鼠标,全键盘操作
- [Java]Java日期及时间库插件 -- Joda Time.
- [转载]Google Guava官方教程(中文版)
- nyoj990蚂蚁感冒
- [Java 缓存] Java Cache之 Guava Cache的简单应用.
- [Java Collection]List分组之简单应用.
- Fiddler抓取Android真机上的HTTPS包
- [Java 缓存] Java Cache之 DCache的简单应用.
- HDU_5754 Life Winner Bo
- 《将博客搬至CSDN》
- UOJ#228——基础数据结构练习题
- 数据库事务隔离级别
- 4个隔离级别
- 第1.3章 node调用dubbo