4

I am working on a coding challenge on a banking application where I need to fetch number of transactions in last 60 seconds. For that I am using java.sql.Timestamp as a key of a map like below:

Map<Timestamp, List<Transaction>> transactions1 = new HashMap<>();

Here value is the list of transactions done at that time. I can't use DB. I know how to iterate through the map and fetch the data but for that I need to iterate the whole map which will be time consuming.

1) My question is is Map the right data structure for this problem?

2) If so then how can I reduce it(may be by NavigableMap)?

I am not asking for coding solution but the proper design/ data structure that I should use.

J. Doe
  • 81
  • 2
  • 3
  • why don't you use epoch timestamp as key `1534698909` so that you sort map based on keys and get the values – Ryuzaki L Aug 19 '18 at 17:16
  • I’d say `Timestamp` is the wrong class. One, it’s long outdated, two, it was designed for use with an SQL database. Consider `Instant` or another class from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Aug 20 '18 at 11:09
  • If all you need is the number of transactions, it suffices to store the number for each time (you don’t need the list of actual transactions). I’d consider a list of pairs of time and number, keeping the list sorted by time. Then it suffices to find the earliest count within the last minutes and adding up the numbers from that point. We don’t know enough about your requirements to tell whether this a good solution, though, which is why I voted to close your question an unclear. – Ole V.V. Aug 20 '18 at 12:15

2 Answers2

3

A HashMap solely considers mapping (based on hash code and equality).

This means: you have to get() all keys of your map, to ensure you correctly identify those within a certain interval. No shortcuts possible, always a full O(n) scanning of all keys in your map.

Thus you are correct: any efficient strategy must allow you to search that map (in an array/random access based approach), so maps implementing the NavigableMap, such as TreeMap will be a better choice. TreeMaps are also sorted, so you could implement some way of "binary search" to identify timestamps from the last n seconds. Meaning: you need O(log n) to determine the first timestamp within the interval, and then you just keep fetching the following keys, until you reach the upper bound of the interval.

Beyond that, it could be helpful to invest in your own implementation of some sort of index. Like a list that remembers the first timestamp of 1/5/n minute intervals.

Meaning: the low hanging fruit is to simply change from HashMap to TreeMap, with clever searching for interval boundaries. But for a "real world" scenario, where you might have to deal with hundreds of thousands or millions of entries, that approach is still not sufficient. Then you would have to very carefully design a solution that optimizes on your most important requirements. But that is something that only you can do.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
1

One way to increase performance is to dump the inner for loop. By adding a List<Transaction> in the HashMap you'll have to use a loop inside another loop to access the Transaction object.


Use,

HashMap<Long, Transaction> transactions = new HashMap<>();

And use Nanoseconds as the key.

System.nanoTime();

So when iterating you have the Transaction object right away. If you want to get the Timestamp,

new Timestamp(nanoseconds/1000000);
Roshana Pitigala
  • 8,437
  • 8
  • 49
  • 80
  • Still, this means to iterate the map in **full** length, based on a non-sorted order. Sure, your idea makes the lookup a bit faster, but it still means that you always always always have to go through **all** entries in the map. Because you have to check each and any key. This mean you have O(n). All the time. Compare that with sorting the keys, and being able to do binary search to identify the first key that needs to be considered! – GhostCat Aug 19 '18 at 17:45
  • But there could be scenario where there were two transactions at the same time. In that case the value will be overwritten. I know nanoseconds is less chance but quite possible right? – J. Doe Aug 20 '18 at 03:30
  • @J.Doe yeah, it's possible. But it's very rare like 1 million : 1. – Roshana Pitigala Aug 20 '18 at 04:03
  • `System.nanotime()` doesn’t give you a well-defined point in time, so you are not obtaining a valid timestamp. `Instant.now()` is an option. – Ole V.V. Aug 20 '18 at 11:14