'efficient lookup where key is a set of key-value pairs pointing to an object

I seek for some inspirations. my problem is how to pool an object identified by key-value pairs. I am working on JVM and don't want to create garbage when creating those objects in runtime - that's why an idea of pooling.

so lets give some example - user can provide identifiers like (A(1) B(4)), (A(1) B(2) C('foo') E(0)), (B(4) A(1)), (A(0)), etc.. - for each of those set of pairs I would like to get unique reference to object created earlier. mind that (A(1) B(4)) and (B(4) A(1)) should point to exactly the same ref - of course I can sort by keys and then perform calculation.

of course I could create a map in runtime as a key and keep a Map<Map<K,V>, T> but this is not really efficient when we talk about X thousands of lookup per second.

I was thinking about hashing those input pairs to get unique id - but somehow I have to prove that hashing function will have no collisions when number or variety of k-v increase in runtime. I expect to have no more than 1M of unique k-v pairs, so computing an id would be the best solution and map that id to an object - but I need function that will calculate such id.

maybe some smart graph structure could be a solution, the only trouble I have is that not only keys create a graph but also values of those keys.

any help would be appreciated.



Solution 1:[1]

I ve solve this particular problem with having a instance of Key builder per thread, key builder holds an array of objects - this array is of known size as we have strictly defined keys (in example it was A,B,C, etc - so we know ordinal of that key).

I dont allocate anything for each request execution, we reuse builder's to set key-values in the array and once that is done I can use the key to find or create object identified by those K-V. also this approach solves problem of order, as it doesnt matter whether somebody identified object by (A(1) B(4)) or (B(4) A(1)) - to follow the example.

I could use Map instead of Objects[], but at least implementation of java.util.HashMap allocates lots of node objects, and I will clear such map for every request! If you use a Map that caches nodes - then maybe this is a way to go.

Solution 2:[2]

Here is a working version

I assume we want to keep the month array in case you want the string representation of the month

const pad = num => String(num).padStart(2, "0"),
  months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
  days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"],
  tags = ["mon", "d", "y", "h", "m", "s", "day"],
  updateClock = div => {
    let now = new Date();
    let sec = now.getSeconds();
    let min = now.getMinutes();
    let hou = now.getHours();
    let mo = now.getMonth();
    let dy = now.getDate();
    let day = now.getDay();
    let yr = now.getFullYear().toString().slice(-2);
    corr = [months[mo], pad(dy), yr, pad(hou), pad(min), pad(sec), days[day]];
    tags.forEach((tag, i) => div.querySelector("." + tag).textContent = corr[i]);
    if (hou < 12) {
      var ampm = "MORNING"
    }
    if (hou >= 12 && hou <= 18) {
      var ampm = "AFTERNOON"
    }
    if (hou > 18) {
      var ampm = "EVENING"
    }
    div.querySelector(".ampm").innerHTML = ampm;
  };
window.addEventListener("load", function() {
  setInterval(function() {
    document.querySelectorAll(".timer").forEach(div => updateClock(div))
  }, 1000)
})
<div id="clock1" class="timer">
  <span class="mon"></span>/<span class="d"></span>/<span class="y"></span> (<span class="day"></span>)
  <span class="h"></span>:<span class="m"></span>:<span class="s"></span> <span class="ampm"></span>
  </div>
<div id="clock2" class="timer">
<span class="day"></span> <span class="ampm"></span> at <span class="h"></span>:<span class="m"></span>:<span class="s"></span> on the 
  <span class="mon"></span>/<span class="d"></span>/<span class="y"></span>
  
  </div>

Using offsets in seconds stored in data-attribute

const pad = num => String(num).padStart(2, "0"),
  months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
  days = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"],
  tags = ["mon", "d", "y", "h", "m", "s", "day"],
  updateClock = div => {
    let now = new Date();
    let offset = div.dataset.offset * 1000
    now.setTime(now.getTime() + offset)
    let sec = now.getSeconds();
    let min = now.getMinutes();
    let hou = now.getHours();
    let mo = now.getMonth();
    let dy = now.getDate();
    let day = now.getDay();
    let yr = now.getFullYear().toString().slice(-2);
    corr = [months[mo], pad(dy), yr, pad(hou), pad(min), pad(sec), days[day]];
    tags.forEach((tag, i) => div.querySelector("." + tag).textContent = corr[i]);
    if (hou < 12) {
      var ampm = "MORNING"
    }
    if (hou >= 12 && hou <= 18) {
      var ampm = "AFTERNOON"
    }
    if (hou > 18) {
      var ampm = "EVENING"
    }
    div.querySelector(".ampm").innerHTML = ampm;
  };
window.addEventListener("load", function() {
  setInterval(function() {
    document.querySelectorAll(".timer").forEach(div => updateClock(div))
  }, 1000)
})
<div id="clock1" class="timer" data-offset="176400">
  <span class="mon"></span>/<span class="d"></span>/<span class="y"></span> (<span class="day"></span>)
  <span class="h"></span>:<span class="m"></span>:<span class="s"></span> <span class="ampm"></span>
  </div>
<div id="clock2" class="timer" data-offset="0">
<span class="day"></span> <span class="ampm"></span> at <span class="h"></span>:<span class="m"></span>:<span class="s"></span> on the 
  <span class="mon"></span>/<span class="d"></span>/<span class="y"></span>
  
  </div>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 kamiseq
Solution 2