高效判断是否连续出现逻辑

实现思路

/**
     * 是否连续n天出现,实现逻辑:指定时间段,获取该时间段内检索结果,根据时间段判断是否连续出现
     * @param results
     * [
     *     {
     *         "record": {
     *             "createTime": "2020-06-17T09:13:00.051Z",
     *             "id": "xxxxxxxxx",
     *         },
     *         "money": 22
     *     }
     * ]
     * 计算逻辑解释:假设有4条分别在前1,2,3,3天出现,则每天命中值为1<<1, 1<<2, 1<<3, 1<<3, 判断是否在前3天连续出现,
     * 只需将每条记录的命中值联合取|,即2,4,8,8一起取| => 2|4|8|8,判断其结果与(2^3)-1是否相等即可。相等则连续,不等则非连续
     *
     * @return
     */
    private boolean checkContinuousAppear(List<User> results) {
        if (CollectionUtils.isEmpty(results)) {
            throw new IllegalArgumentException("user results can't be null or empty!");
        }
        List<Integer> hitsCollection = results.stream().map(e -> hitBit(e.getRecord().getCreateTime())).collect(Collectors.toList());
        Integer result = hitsCollection.stream().reduce((x1, x2) -> x1 | x2).get();
        if (result.equals((1 << bizConfig.getContinuousOccurDays()) - 1)) {
            return true;
        }
        return false;
    }

    /**
     * 使用移位记录每个时间点是否命中
     * 1 2 4 8 16 32 .....
     *
     * @param time
     * @return
     */
    private int hitBit(Instant time) {
        LocalDate beforeNDate = LocalDate.now().minusDays(bizConfig.getContinuousOccurDays());
        for (int i = 0; i < bizConfig.getContinuousOccurDays(); i++) {
            Instant start, end;
            if (i == 0) {
                start = beforeNDate.atStartOfDay().toInstant(ZoneOffset.UTC);
            } else {
                start = beforeNDate.plusDays(i).atStartOfDay().toInstant(ZoneOffset.UTC);
            }
            end = beforeNDate.plusDays(i + 1).atStartOfDay().toInstant(ZoneOffset.UTC);
            if (hitTime(time, start, end)) {
                return 1<< i;
            }
        }
        return 1;
    }
/**
     * 判断给定时间是否在时间区间内
     * @param target
     * @param start
     * @param end
     * @return
     */
    private boolean hitTime(Instant target, Instant start, Instant end) {
        if (target.toEpochMilli() >= start.toEpochMilli() && target.toEpochMilli() <= end.toEpochMilli()) {
            return true;
        }
        return false;
    }

此逻辑同样可推广至最近n小时,n分钟,n秒之类的判断

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值