0

I have a sorted JavaScript map structure storing object states based on time.
Map(key:time(inMilli), value: {object attributes})

What I am needing to accomplish is to be able to check map against a start and end time to get a collection of all values between without iterating over the entirety of the map.

//currently using something like this. But would like to not compare against entire map of times
let map = dataService.getTimeData()//returns map of all objects
let updates = getRange(someTime, someTime);

function getRange(start, stop){
  let foundValues = [];
  //if start is end or after end time
  if(start >== stop)return [start];

  //search map for values
  for([key,value] of map){
    if(key > start && key < stop)foundValues.push(key)
  }  
  return foundValues;
}
Zachary Evans
  • 21
  • 1
  • 7
  • I've not used a map, but couldn't you just use `map.keys()` and iterate over that? – Jhecht Sep 13 '18 at 18:58
  • yes but that would still require iterating over the entirety of the map. What I am looking for is a way to essentially grab two indexes and only iterate over the times that I need. – Zachary Evans Sep 13 '18 at 19:35
  • as I said, I've not used Map, but from what I know of Maps I don't think you'll be able to accomplish this without going over the entirety of the array. – Jhecht Sep 13 '18 at 19:38
  • 1
    Yea, that was my initial assumption but was really hoping that someone would have found a way lol. I did find a library and posted in solution that allows for this and is really handy for client-side data storage and retrieval. Have not tested performance yet but it is looking pretty good. – Zachary Evans Sep 13 '18 at 19:50

2 Answers2

0
function getRange(start, stop){

    let foundValues = [];

    if (start >== stop) return [start];

    for(let [key, value] of map.entries()){
        if (key > start && key < stop) {
            foundValues.push(key);
        } else {
            return foundValues;
        }
    }  
    return foundValues;
}

You just need to return the array once an entry's time in the map is out of the specified range(start and stop), and this will stop the iteration.

function getRange(start, stop) {

  const currentArray = Array.from(map);

  let foundValues = [];
  let currentMap = currentArray.shift();

  while (currentMap[0] > start && currentMap[0] < stop && currentArray.length) {
    foundValues.push(currentMap[1]);
    currentMap = currentArray.shift();
  }

  return foundValues;

}

Using while loop, this won't iterate all the items in the map. This will only work when the map is already sorted.

oosniss
  • 440
  • 1
  • 7
  • 14
  • This is similar to what I had come up with but really did not want the overhead of converting the entire map to an array. Ended up finding a library called jstree that has a javascript TreeMap with upper and lower bounds functions that can be used for segmenting the map like I was needing. – Zachary Evans Sep 13 '18 at 19:39
0

Ended up using jstreemap and using a TreeMap and itterating over their upper and lower bounds functions. This was really easy and would recommend.

let map = new TreeMap();//just wanted to show that this is a TreeMap now
map = dataService.getData();

function getRange(startTime, endTime){
  let from = map.lowerBound(startTime);
  let to = map.upperBound(endTime);
  let it = from;//initialize to first value in iterator
  let foundValues = [];

  //only iterates from first object requested to last. No longer needs to search any unnecessary values. 
  while(!it.equals(to)){
    foundValues.push(it);
    it.next();
  }
  return foundValues();
}
Zachary Evans
  • 21
  • 1
  • 7