0

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))

1 Answer 1

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)))))
         (full-list (cl-sort full-list (lambda (node-stamp1 node-stamp2) (< (caadr node-stamp1) (caadr node-stamp2)))))
         (current-pos (cl-position-if (lambda (node-stamp) (< (abs (- (caadr node-stamp) time-stamp)) goto-node-timestamp-tolerance)) full-list)))
    (assert current-pos nil "Timestamp not found in 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))
1
  • 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
    Commented May 2, 2017 at 1:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.