# Custom function to map through nested lists sorting by time-stamp

In the following example, please assume that we are using `time-to-seconds` to convert each times-stamp into a decimal representation. I have already converted the time-stamps to seconds in this example. Each node has at least one time-stamp, but there might be more than one time-stamp per node. The current node with corresponding time-stamp is represented by a `cons` cell with the `cdr` being `t`. The time-stamps will always be unique. The nodes are vectors with multiple elements.

``````(defun goto-node (time-stamp n)
"Go to the desired node commencing from an existing TIME-STAMP.
If N is positive, then go forwards in time by that number of N time-stamps.
If N is negative, then backwards in time by that number of N time-stamps.
If node does not exist, return nil; otherwise, return node and corresponding time-stamp."

INSERT MAGIC HERE)
``````

BEGIN WITH:

``````'(([node1] ((5.6) (3.7) (11.7) (8.2)))
([node2] ((4.4) (9.9) (6.1 . t)))
([node3] ((7.5) (2.3) (1.5)))
([node4] ((10.3))))
``````

EXAMAPLES:

`(goto-node 6.1 -1)` => `'([node1] (5.6))`

`(goto-node 6.1 -4)` => `'([node3] (2.3))`

`(goto-node 6.1 1)` => `'([node3] (7.5))`

`(goto-node 6.1 4)` => `'([node4] (10.3))`

Generate a complete (`rassoc`-) map assigning time-stamps to nodes at first. Afterwards sort and then locate `time-stamp` in the sorted list. From there you can go forward and backward.

``````(defvar goto-node-timestamp-tolerance 1e-5
"Tolerance for testing equality of timestamps.")

(defun goto-node (list time-stamp n)
"Go to the desired node commencing from an existing TIME-STAMP in LIST.
If N is positive, then go forwards in time by that number of N time-stamps.
If N is negative, then backwards in time by that number of N time-stamps.
If node does not exist, return nil; otherwise, return node and corresponding time-stamp."
(let* ((full-list (apply #'append
(loop for node-stamps in list
collect (mapcar (lambda (stamp) (list (car node-stamps) stamp)) (cadr node-stamps)))))
(current-pos (cl-position-if (lambda (node-stamp) (< (abs (- (caadr node-stamp) time-stamp)) goto-node-timestamp-tolerance)) full-list)))
(nth (max (min (+ current-pos n) (1- (length full-list))) 0) full-list)))

(setq l '(([node1] ((5.6) (3.7) (11.7) (8.2)))
([node2] ((4.4) (9.9) (6.1 . t)))
([node3] ((7.5) (2.3) (1.5)))
([node4] ((10.3)))))

(goto-node l 6.1 -1) ; => '([node3] (5.6))

(goto-node l 6.1 -4) ; => '([node3] (2.3))

(goto-node l 6.1 1) ; => '([node3] (7.5))

(goto-node l 6.1 4) ; => '([node4] (10.3))
``````
• A few observations: (1) `time-to-seconds` creates a decimal of six places, so we should probably be using `1e6`. (2) The conversion from `time-to-seconds` and `seconds-to-time` again is not precise and the original timestamp is not the exact same after going through the washing machine and dryer. Therefore, I created a list with the best of both worlds -- e.g, `(([node1] (((1493686266.992367 (22791 55290 992367 0)) t))))`. By adding a `car` to the front of each `caadr`, the seconds are used to do comparisons while the result still contains the original timestamp unchanged. – lawlist May 2 '17 at 1:08