Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
bobbysmith007 committed May 18, 2011
1 parent 2a6cf13 commit adbbfa9
Show file tree
Hide file tree
Showing 6 changed files with 778 additions and 0 deletions.
20 changes: 20 additions & 0 deletions LICENSE
@@ -0,0 +1,20 @@
;; Copyright (c) 2011 Russ Tyndall , Acceleration.net http://www.acceleration.net

;; Permission is hereby granted, free of charge, to any person obtaining
;; a copy of this software and associated documentation files (the
;; "Software"), to deal in the Software without restriction, including
;; without limitation the rights to use, copy, modify, merge, publish,
;; distribute, sublicense, and/or sell copies of the Software, and to
;; permit persons to whom the Software is furnished to do so, subject to
;; the following conditions:

;; The above copyright notice and this permission notice shall be
;; included in all copies or substantial portions of the Software.

;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 changes: 26 additions & 0 deletions README.mediawiki
@@ -0,0 +1,26 @@
= group-by =
A Common Lisp library to help group data into trees (of various
formats) based on common/shared values


== API ==
=== group-by ===
groups the list into an alist using the key function and value function to group by key,
with a list of all values for that key.

key is used to determine the key in the a-list <br />
value is used to determin the value in the a-list <br />
key-fn is passed as the :key to assoc (essentially the key of your key) <br />
test is passed as the :test to assoc <br />

eg: (group-by '((a 1 2) (a 3 4) (b 5 6)))
=> ((A (1 2) (3 4)) (B (5 6)))

eg: (group-by '((a 1 2) (a 3 4) (b 5 6)) :value #'identity)
=> ((A (A 1 2) (A 3 4)) (B (B 5 6)))


=== grouped-list ===

== Examples ==
See the examples file and the tests for running examples
138 changes: 138 additions & 0 deletions examples/examples.lisp
@@ -0,0 +1,138 @@
(in-package :group-by)

(defparameter +example-timeclock-data+
`(("russ" 1 :proj-a)
("russ" 2 :proj-a)
("bob" 1 :proj-a)
("russ" 2 :proj-b)
("bob" 1 :proj-b)
("bob" 1 :proj-b)
("russ" 2 :proj-b)
("bob" 1 :proj-c)
("russ" 4 :proj-c)))

(group-by +example-timeclock-data+)
;; results in
'(("russ"
(1 :proj-a) (2 :proj-a) (2 "time on proj b")
(2 "time on proj b") (4 :proj-c))
("bob"
(1 :proj-a) (1 "time on proj b") (1 "time on proj b")
(1 :proj-c)))

(defparameter +example-multiple-grouped-timeclock-data+
(group-by-repeated
+example-timeclock-data+
:keys (list #'first #'third)
:tests (list #'string-equal #'eql)))
;; results in
'(("bob"
(:proj-c ("bob" 1 :proj-c))
(:proj-b ("bob" 1 :proj-b) ("bob" 1 :proj-b))
(:proj-a ("bob" 1 :proj-a)))
("russ"
(:proj-c ("russ" 4 :proj-c))
(:proj-b ("russ" 2 :proj-b) ("russ" 2 :proj-b))
(:proj-a ("russ" 2 :proj-a) ("russ" 1 :proj-a))))

(defparameter +example-grouped-list-timeclock-data-alist+
(make-grouped-list
+example-timeclock-data+
:keys (list #'first #'third)
:tests (list #'string-equal #'eql)))

(defclass example-timeclock-record ()
((name :accessor name :initarg :name :initform nil)
(hours :accessor hours :initarg :hours :initform 0)
(proj :accessor proj :initarg :proj :initform nil)))

(defun example-tcr (name hours proj)
(make-instance 'example-timeclock-record :name name :hours hours :proj proj))

(defparameter +example-timeclock-objs+
(iter top (for i from 0 to 10)
(iter (for rec in +example-timeclock-data+)
(in top (collect (apply #'example-tcr rec))))))

(defun print-timeclock-report ()
(labels ((print-results (gl &optional (spaces ""))
(let ((further-groups (child-groupings gl)))
(if further-groups
(iter
(with hours = 0)
(for group in further-groups)
(format T "~?~A~%" spaces () (key-value group) )
(incf hours (print-results group (concatenate 'string spaces "~2,1@T")))
(finally
(format T "~?Total: ~D~%" spaces () hours )
(return hours)))
(iter (for kid in (items-in-group gl))
(sum (hours kid) into hours)
(finally
(format T "~?Total: ~D~%" spaces () hours )
(return hours)))))))

(let ((by-person-project
(make-grouped-list
+example-timeclock-objs+
:keys (list #'name #'proj)
:tests (list #'string-equal #'eql)
:grouping-implementation :hash-table))
(by-project-person
(make-grouped-list
+example-timeclock-objs+
:keys (list #'proj #'name)
:tests (list #'eql #'string-equal)
:grouping-implementation :tree)))

(format T "Hours BY Project > Person~%-----------~%")
(print-results by-project-person)
(format T "~%~%Hours BY Person > Project~%-----------~%")
(print-results by-person-project)
)))

#|
Hours BY Project > Person
-----------
PROJ-C
russ
Total: 44
bob
Total: 11
Total: 55
PROJ-B
bob
Total: 22
russ
Total: 44
Total: 66
PROJ-A
bob
Total: 11
russ
Total: 33
Total: 44
Total: 165
Hours BY Person > Project
-----------
russ
PROJ-A
Total: 33
PROJ-B
Total: 44
PROJ-C
Total: 44
Total: 121
bob
PROJ-A
Total: 11
PROJ-B
Total: 22
PROJ-C
Total: 11
Total: 44
Total: 165
|#

50 changes: 50 additions & 0 deletions group-by.asd
@@ -0,0 +1,50 @@
;; -*- lisp -*-

(eval-when (:compile-toplevel :load-toplevel :execute)
(unless (find-package :group-by.system)
(defpackage :group-by.system
(:use :common-lisp :asdf))))

(in-package group-by.system)

(defsystem :group-by
:description "A Common Lisp library to help group data into trees (of various
formats) based on common/shared values"
:licence "BSD"
:version "0.1"
:components ((:file "group-by"))
:depends-on (:iterate :alexandria))

(defsystem :group-by-test
:description "A Common Lisp library to help group data into trees (of various
formats) based on common/shared values"
:licence "BSD"
:version "0.1"
:components ((:module :tests
:serial t
:components ((:file "group-by"))))
:depends-on (:group-by :lisp-unit))

(defmethod asdf:perform ((o asdf:test-op) (c (eql (find-system :group-by))))
(asdf:oos 'asdf:load-op :group-by-test))

;; Copyright (c) 2011 Russ Tyndall , Acceleration.net http://www.acceleration.net

;; Permission is hereby granted, free of charge, to any person obtaining
;; a copy of this software and associated documentation files (the
;; "Software"), to deal in the Software without restriction, including
;; without limitation the rights to use, copy, modify, merge, publish,
;; distribute, sublicense, and/or sell copies of the Software, and to
;; permit persons to whom the Software is furnished to do so, subject to
;; the following conditions:

;; The above copyright notice and this permission notice shall be
;; included in all copies or substantial portions of the Software.

;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0 comments on commit adbbfa9

Please sign in to comment.