-1

I need help to find out how to find something in java which is currently being done in sql. I need to find specific data in a list within a specific time duration using streams

scenario: I have a Bet Object with String CustId, Instant timestamp, Double betAmount

I need to find all customers which passed the 100.00 limit per 24 hour period, how would i do it in Java 8?

The method would be

public List<String> findLimits(List<Bet> bets){
...
}

sample data :

note: to be parsed in List<Bet>

A00001    2019-01-15T02:01:10   43.00
A00001    2019-01-15T04:00:00   13.00
A00001    2019-01-15T04:01:15   50.00
B00034    2019-01-15T05:00:00   15.00
A00001    2019-01-15T06:56:20   5.00
B00034    2019-01-15T06:57:00   20.00
C00004    2019-01-15T07:01:00   90.00
C00004    2019-01-15T07:11:00   30.00
B00034    2019-01-17T01:00:00   90.00

expected result:

["A00001","C00004"] (List<String>)

note: the list would contain all bets with diff cust id and chronological timestamps

The sliding 24 hour period and grouping the customers combined is a tricky one that i'm trying to solve.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
gigz
  • 942
  • 2
  • 9
  • 26
  • Group things by the customer ID; then filter the entry set to only contain values which match your criterion; then discard the values. The "matching your criterion" bit can just be a simple method that uses two pointers to slide over the points, keeping track of the sum of bets between the pointers. – Andy Turner Mar 17 '19 at 22:41
  • Would this answer about sliding window stream operations help https://stackoverflow.com/a/34159174/2615510 ? – Andrey Lebedenko Mar 18 '19 at 20:55

2 Answers2

2

You can map dates with the sum of bet amounts. Then filter them.

public List<String> findLimits(List<Bet> bets) {
    return bets.stream()
            .collect(Collectors.toMap(
                    b -> b.getCustId() + LocalDate.ofInstant(b.getTimestamp(), ZoneOffset.UTC).toString(),
                    Bet::getAmount,
                    (o1, o2) -> o1 + o2))
            .entrySet().stream()
            .filter(e -> e.getValue() > 100.0)
            .map(e -> e.getKey().substring(0, e.getKey().length() - LocalDate.EPOCH.toString().length()))
            .collect(Collectors.toList());
}
Kartik
  • 7,677
  • 4
  • 28
  • 50
1

Firstly you can group data by customer ID and then analyze sums in 24h periods. As you mentioned records are sorted by date ascending, so findLimits method can look like below:

class Bet {
    String ID;
    LocalDateTime dateTime;
    BigDecimal value;
}

public List<String> findLimits(List<Bet> bets) {
    BigDecimal sumLimit = new BigDecimal(100);
    Map<String, List<Bet>> map = new HashMap<String, List<Bet>>();
    List<String> result = new ArrayList<String>();
    for (Bet bet : bets) {
        if (map.get(bet.ID) == null)
            map.put(bet.ID, new ArrayList<Bet>());
        map.get(bet.ID).add(bet);
    }

    for (String ID : map.keySet()) {
        List<Bet> betListForCustomer = map.get(ID);
        boolean customerExceededLimit = false;
        for (int i = 0; i < betListForCustomer.size(); i++) {
            LocalDateTime endOfPeriod = betListForCustomer.get(i).dateTime.plusDays(1); //calculating end of 24h period current data
            BigDecimal sum = new BigDecimal(0);
            for (int j = i; j < betListForCustomer.size() //move start period to next dateTime
                    && endOfPeriod.isAfter(betListForCustomer.get(j).dateTime); j++) { //analyzing to the last date in 24h period or end data set
                sum = sum.add(betListForCustomer.get(j).value);
            }
            if (sum.compareTo(sumLimit) >= 0) { //sum >= 100
                customerExceededLimit = true;
                break; //there is no need to analyze this customer, limit exceeded
            }
        }
        if (customerExceededLimit) {
            result.add(ID);
        }
    }
    return result;
}
glw
  • 1,646
  • 1
  • 16
  • 20