Treemap application in data statistical analysis (sorting and finding the closest key to the specified key)

1. Application scenarios


The logic of statistics by day uses hashmap for storage, which has been mentioned in another article. The problem now is the transaction record table queried. If there is no transaction record on the day, the flow balance is 0. This is wrong. It should be the flow balance of the latest transaction record.

1. Must be in order

2. Ability to query the most recent key

At this time, hashmap cannot meet the requirements. Try treemap, the first choice for map order. I checked the api, and it actually supports it. I use the lowerKey method.

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. How to use

  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) {
                    //In the case of no transaction record
                    Date minDate = null;
                    try {
                        minDate = DateUtils.getDateFromStr(minDateString);
                    } catch (Exception e) {
                    }
                    if (DateUtils.getDaysBetweenDates(currentDay, minDate) < 0) {
                        //Less than the earliest recharge record date, set to 0
                        remainingFluxMap.put(DateUtils.dateToStr(DateUtils.getDateIgnoreTime(currentDay), 11), new BigDecimal(0));
                    } else {
                        //find the most recent record
                        Map.Entry<String, BigDecimal> availableChargeItemEntry = remainingFluxMap.lowerEntry(currentDayStr);
                        if (availableChargeItemEntry != null) {
                            remainingFluxMap.put(currentDayStr, availableChargeItemEntry.getValue());
                        }

                    }

                }

            }

        }
        return remainingFluxMap;
    }
1. The lowerKey method looks for the one that is smaller than the specified key and the largest one. It should be noted that many articles say that it is the previous key, which is not accurate. The specified key does not have to exist in the map. For example, my designated key is one of the selected dates, which does not exist in the map.

2. Concise writing of comparators

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

     Arraylist does not have a constructor to set the comparator, you can use the following notation:

Comparator<ChannelRank> comparator=Comparator.comparing(ChannelRank::getRankScore).reversed();
            channelRankList.sort(comparator);

    or

Comparator<VoTransaction> comparator = (h1, h2) -> h2.getTime().compareTo(h1.getTime());

3. If the declaration is Map treeMap=new TreeMap(), there is only the interface of map, and there are no methods such as lowerKey. Because treemap implements the NavigableMap interface in addition to the map interface

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{
4. In addition to the comparator, by the way, the list to filter function, although this case is not used

  List<ChannelDownStreamInfo> channelDownStreamInfoList = channelDownStreamInfoDbList.stream().filter(channelDownStreamInfoDb ->
                        channelDownStreamInfoDb.getChannelFlag().equalsIgnoreCase(channelDownStreamInfo.getChannelFlag()
                ) ).collect(Collectors.toList());
5. Supplementary knowledge point The role of lamda expression

The function is only used once, I don't want to define the name, and I don't want to write a complex function structure. At this time, the wine uses the lamda expression

For example, the filter function of the above list, if the lamda expression is not used, the predicted interface will be implemented in the filter, as follows:

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();
            }
In contrast, lamda expressions are much more concise.






Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325420187&siteId=291194637