История изменений
Исправление Jini, (текущая версия) :
На с++
До кучи два моих варианта. В C++ используется перегрузка operator<, вот также на лиспе:
(defstruct person
(name "" :type string)
(department-id 0 :type fixnum))
(defgeneric less (a b))
(defmethod less ((a real) (b real))
(< a b))
(defmethod less ((a string) (b string))
(string< a b))
(defmethod less ((a sequence) (b sequence))
(eq (some (lambda (x y)
(cond
((less x y) t)
((less y x) '#:false)))
a b)
t))
(defun make-test-persons ()
(loop
:repeat 10
:collect (make-person :name (format nil "name~d" (random 10))
:department-id (random 3))))
(defun test-3.1 ()
(sort (make-test-persons) #'less
:key (lambda (person)
(list (person-department-id person)
(person-name person)))))
(defun test-3.2 ()
(sort (make-test-persons) #'string< :key #'person-name))
В отличие от C++, перегрузка идёт в рантайме. Также есть оверхед в создании списков при каждом вызове оператора сравнения структур. От этого можно избавиться макросами, как обычно:
(defmacro multiple-less ((a b) &body clauses)
(let ((original-a (gensym "A"))
(original-b (gensym "B")))
(labels ((less (clauses)
(destructuring-bind (form &optional (key #'identity)) (pop clauses)
`(let ((,a (funcall ,key ,original-a))
(,b (funcall ,key ,original-b)))
,(if clauses
`(cond
(,form
t)
((let ((,a ,b) (,b ,a))
,form)
nil)
(t
,(less clauses)))
form)))))
(if clauses
`(lambda (,original-a ,original-b)
,(less clauses))
(constantly t)))))
(defun test-3.1* ()
(sort (make-test-persons)
(multiple-less (a b)
((< a b) #'person-department-id)
((string< a b) #'person-name))))
Я думаю, что если поколдовать с декларациями, этот код будет эквивалентен C++ в плане скорости.
Исходная версия Jini, :
На с++
До куч два моих варианта. В C++ используется перегрузка operator<, вот также на лиспе:
(defstruct person
(name "" :type string)
(department-id 0 :type fixnum))
(defgeneric less (a b))
(defmethod less ((a real) (b real))
(< a b))
(defmethod less ((a string) (b string))
(string< a b))
(defmethod less ((a sequence) (b sequence))
(eq (some (lambda (x y)
(cond
((less x y) t)
((less y x) '#:false)))
a b)
t))
(defun make-test-persons ()
(loop
:repeat 10
:collect (make-person :name (format nil "name~d" (random 10))
:department-id (random 3))))
(defun test-3.1 ()
(sort (make-test-persons) #'less
:key (lambda (person)
(list (person-department-id person)
(person-name person)))))
(defun test-3.2 ()
(sort (make-test-persons) #'string< :key #'person-name))
В отличие от C++, перегрузка идёт в рантайме. Также есть оверхед в создании списков при каждом вызове оператора сравнения структур. От этого можно избавиться макросами, как обычно:
(defmacro multiple-less ((a b) &body clauses)
(let ((original-a (gensym "A"))
(original-b (gensym "B")))
(labels ((less (clauses)
(destructuring-bind (form &optional (key #'identity)) (pop clauses)
`(let ((,a (funcall ,key ,original-a))
(,b (funcall ,key ,original-b)))
,(if clauses
`(cond
(,form
t)
((let ((,a ,b) (,b ,a))
,form)
nil)
(t
,(less clauses)))
form)))))
(if clauses
`(lambda (,original-a ,original-b)
,(less clauses))
(constantly t)))))
(defun test-3.1* ()
(sort (make-test-persons)
(multiple-less (a b)
((< a b) #'person-department-id)
((string< a b) #'person-name))))
Я думаю, что если поколдовать с декларациями, этот код будет эквивалентен C++ в плане скорости.