您的位置:首页 > 其它

数据统计分析中Treemap 应用实战(排序以及查找离指定key最近的key)

2018-01-30 19:14 701 查看

1. 应用场景




按天统计的逻辑利用hashmap进行存储,另外一篇文章已经提到。现在的问题是查询的交易记录表,如果当天没有交易记录,流量余额就是0,这个是不对的,应该是最近一笔交易记录时的流量余额。

1.必须有序

2.能够查询最近的一个key

此时hashmap不能满足要求,试试treemap,map有序的首选。查询了一下api,竟然支持,我利用的是lowerKey方法

Map.Entry<K,V>
firstEntry()


Returns a key-value mapping associated with the least key in this map, or 
null
 if the map is empty.
K
firstKey()


Returns the first (lowest) key currently in this map.
Map.Entry<K,V>
floorEntry(K key)


Returns a key-value mapping associated with the greatest key less than or equal to the given key, or 
null
 if there is no such key.
K
floorKey(K key)


Returns the greatest key less than or equal to the given key, or 
null
 if there is no such key.
Map.Entry<K,V>
higherEntry(K key)


Returns a key-value mapping associated with the least key strictly greater than the given key, or 
null
 if there is no such key.
K
higherKey(K key)


Returns the least key strictly greater than the given key, or 
null
 if there is no such key.
Set<K>
keySet()


Returns a 
Set
 view
of the keys contained in this map.
Map.Entry<K,V>
lastEntry()


Returns a key-value mapping associated with the greatest key in this map, or 
null
 if the map is empty.
K
lastKey()


Returns the last (highest) key currently in this map.
Map.Entry<K,V>
lowerEntry(K key)


Returns a key-value mapping associated with the greatest key strictly less than the given key, or 
null
 if there is no such key.
K
lowerKey(K key)


Returns the greatest key strictly less than the given key, or 
null
 if there is no such key.

2. 如何运用

private Map<String, BigDecimal> getRemainingFlux(String channelFlag, Date startTime, Date endTime) {
TreeMap<String, BigDecimal> remainingFluxMap = new TreeMap<>((o1, o2) -> o1.compareTo(o2));
AccountInfoExample accountInfoExample = new AccountInfoExample();
accountInfoExample.createCriteria().andDownChannelFlagEqualTo(channelFlag);
List<AccountInfo> accountInfoList = accountInfoMapper.selectByExample(accountInfoExample);
Long accountId = 0L;
if (CollectionUtils.isNotEmpty(accountInfoList)) {
accountId = accountInfoList.get(0).getId();
}
RechargeInfoExample rechargeInfoExample = new RechargeInfoExample();
rechargeInfoExample.createCriteria().andAccountIdEqualTo(accountId);
rechargeInfoExample.setOrderByClause("create_time asc");
List<RechargeInfo> rechargeInfoList = rechargeInfoMapper.selectByExample(rechargeInfoExample);
if (CollectionUtils.isNotEmpty(rechargeInfoList)) {
rechargeInfoList.forEach(rechargeInfo -> {
String date = DateUtils.dateToStr(rechargeInfo.getCreateTime(), 11);
BigDecimal accountBalance = rechargeInfo.getAccountBalance();
remainingFluxMap.put(date, accountBalance);
});
String minDateString = remainingFluxMap.firstKey();
int gapDays = DateUtils.getDaysBetweenDates(endTime, startTime);
for (int i = 0; i <=gapDays; i++) {
Date currentDay = DateUtils.addDay(startTime, i);
String currentDayStr = DateUtils.dateToStr(DateUtils.getDateIgnoreTime(currentDay), 11);
if (remainingFluxMap.get(currentDayStr) == null) {
//无交易记录情况下
Date minDate = null;
try {
minDate = DateUtils.getDateFromStr(minDateString);
} catch (Exception e) {
}
if (DateUtils.getDaysBetweenDates(currentDay, minDate) < 0) {
//小于最早充值记录日期,设置为0
remainingFluxMap.put(DateUtils.dateToStr(DateUtils.getDateIgnoreTime(currentDay), 11), new BigDecimal(0));
} else {
//寻找最近的一笔记录
Map.Entry<String, BigDecimal> availableChargeItemEntry = remainingFluxMap.lowerEntry(currentDayStr);
if (availableChargeItemEntry != null) {
remainingFluxMap.put(currentDayStr, availableChargeItemEntry.getValue());
}

}

}

}

}
return remainingFluxMap;
}1. lowerKey方法寻找的是小于指定key并且最大的一个,要注意很多文章说是上一个key,这个并不准确。指定的key不一定要在map中存在。比如我的指定key就是选择的日期中的某一天,都不在map中存在。
2. 比较器的简洁写法

TreeMap<String, BigDecimal> remainingFluxMap = new TreeMap<>((o1, o2) -> o1.compareTo(o2));

     arraylist没有构造方法设置比较器,可以利用下面的写法:
Comparator<ChannelRank> comparator=Comparator.comparing(ChannelRank::getRankScore).reversed();
channelRankList.sort(comparator);
    或者

Comparator<VoTransaction> comparator = (h1, h2) -> h2.getTime().compareTo(h1.getTime());
3.  如果声明为Map treeMap=new TreeMap(),则只有map的接口,没有lowerKey这些方法。因为treemap除了实现了map接口,还实现了NavigableMap接口
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{4. 除了比较器,顺便说一下list对filter功能,虽然本case并未运用
List<ChannelDownStreamInfo> channelDownStreamInfoList = channelDownStreamInfoDbList.stream().filter(channelDownStreamInfoDb ->
channelDownStreamInfoDb.getChannelFlag().equalsIgnoreCase(channelDownStreamInfo.getChannelFlag()
) ).collect(Collectors.toList());5. 补充知识点 lamda表达式的作用
只是使用一次的函数,不想去定义名字,也不想去写个复杂的函数结构,这个时候酒用lamda表达式

比如上面list的filter功能,如果不用lamda表达式,filter里面会实现predicted接口,如下:

List<ChannelDownStreamInfo> channelDownStreamInfoList = channelDownStreamInfoDbList.stream().filter(new Predicate<ChannelDownStreamInfo>() {
@Override
public boolean test(ChannelDownStreamInfo channelDownStreamInfoDb) {
return channelDownStreamInfoDb.getChannelFlag().equalsIgnoreCase(channelDownStreamInfo.getChannelFlag());
}
}).collect(Collectors.toList());
channelStateDb = channelDownStreamInfoList.get(0).getChannelState();
}相比之下,lamda表达式简洁很多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐