matcher association list lisp - lisp

Hi everyone I am new to programming and I have to work with association list like this
((course (john .math) (jim .english) (carl .biology) )
(year (john .2) (jim. 1) (carl .3))
(age (john .22) (jim .20) (carl .27))
)
I am supposed to use the matcher to work like that with a function lookup
(lookup 'john 'course data) and return math
Now I am new to programming and completely new to Lisp and need to do this for the school. Now I do not need a complete solution necessary but some ideas or instructions.
This is what I have though so far but took me a lot of time
If someone can help it will be much appreciated!!!!
(defun lookup (name course data)
(matches '(name course data) '(first course ))
)

First let's put the data into a list called data. Pay attention that the list needs to be quoted by ', and that the . dot signs need to be surrounded by spaces because they have a signification of their own:
(defparameter *data* '((course (john . math) (jim . english) (carl . biology))
(year (john . 2) (jim . 1) (carl . 3))
(age (john . 22) (jim . 20) (carl . 27))))
Now let's try using procedure assoc:
? *data*
((COURSE (JOHN . MATH) (JIM . ENGLISH) (CARL . BIOLOGY)) (YEAR (JOHN . 2) (JIM . 1) (CARL . 3)) (AGE (JOHN . 22) (JIM . 20) (CARL . 27)))
? (assoc 'course *data*)
(COURSE (JOHN . MATH) (JIM . ENGLISH) (CARL . BIOLOGY))
? (cdr (assoc 'course *data*))
((JOHN . MATH) (JIM . ENGLISH) (CARL . BIOLOGY))
? (assoc 'john (cdr (assoc 'course *data*)))
(JOHN . MATH)
? (cdr (assoc 'john (cdr (assoc 'course *data*))))
MATH
so the function becomes
(defun lookup (name attr data)
(cdr (assoc name (cdr (assoc attr data)))))
(lookup 'john 'course *data*)
=> MATH
(lookup 'carl 'age *data*)
=> 27

Related

Lisp - bad argument type: numberp: nil

I am writing a function that removes background mask from all mtext, however, I am getting a bad argument type: numberp: nil error after running the code:
(defun c:bgm ()
(vl-load-com)
(setq ss1 (ssget "X" '((0 . "MTEXT")(-4 . "<OR")(90 . 1)(90 . 3)(-4 . "OR>")))); selects all mtext with background mask on
(setq sscount (sslength ss1))
(repeat sscount
(setq mtxtobj (entget (vlax-vla-object->ename (ssname ss1 counter))))
(vla-put-backgroundfill mtxtobj :vlax-false)
(entmod mtxtobj)
)
)
Any ideas why?
There are a number of issues with your code:
If the ssget expression does not obtain a selection (i.e. if there are no objects present in the drawing which fulfil the selection criteria), then ssget will return nil, and consequently the sslength function will error when supplied with a null argument.
To avoid this, test the value returned by the ssget function using an if statement before proceeding with the remaining code:
(if (setq ss1 (ssget "_X" '((0 . "MTEXT") (-4 . "<OR") (90 . 1) (90 . 3) (-4 . "OR>"))))
(progn
(setq sscount (sslength ss1))
...
)
)
You reference the variable counter in your ssname function, which is not defined in the scope of the c:bgm function:
(ssname ss1 counter)
This should instead be sscount as defined earlier in your code.
You seem to be confused between entity names and vla-objects:
ssname returns an entity name, however, you are passing this to the vlax-vla-object->ename function, which converts a vla-object to an entity name.
You are using the vla-put-backgroundfill function to change the backgroundfill property of a vla-object, however, you are passing this function the variable defined by the value returned by entget, which is a DXF data list, not a vla-object.
You are using entmod to modify the DXF data assigned to the variable mtxtobj - this is not required when changing ActiveX properties of a vla-object.
Taking the above into consideration, I would suggest the following solution:
(defun c:bgm ( / cnt obj sel )
(if (setq sel (ssget "_X" '((0 . "MTEXT") (-4 . "<OR") (90 . 1) (90 . 3) (-4 . "OR>"))))
(repeat (setq cnt (sslength sel))
(setq cnt (1- cnt)
obj (vlax-ename->vla-object (ssname sel cnt))
)
(vla-put-backgroundfill obj :vlax-false)
)
)
(princ)
)
(vl-load-com) (princ)
The error is probably due to:
(ssname ss1 counter)
where counter is nil.
You should use sscount instead. You also have to decrement the sscount value to iterate through the selection set.
(defun c:bgm (/ ss1 sscount)
(vl-load-com)
(if (setq ss1 (ssget "X" '((0 . "MTEXT") (-4 . "<OR") (90 . 1) (90 . 3) (-4 . "OR>"))))
(repeat (setq sscount (sslength ss1))
(setq sscount (1- sscount)
mtxtobj (vlax-vla-object->ename (ssname ss1 sscount))
)
(vla-put-backgroundfill mtxtobj :vlax-false)
)
)
)

Using remove-if-not with &key parameters

I have the following code, which is supposed to be a higher-order function that filters elements based on the &key arguments entered (in this case :year, :month and :type.
(defun filter-by (&key year month type)
"Remove members of the list not matching the given year and/or month and/or type, returns a
function that takes the list"
(lambda (lst)
(remove-if-not #'(lambda (element)
(when year
(equalp (local-time:timestamp-year (get-record-date element))
year)))
(when month
(equalp (local-time:timestamp-month (get-record-date element))
month)))
(when type
(equalp (get-type element)
type))))
lst)))
The problem is that unless all the keyword arguments are used, it will always return nil, I'm guessing because of how the when form behaves inside remove-if-not.
Is there anyway to make this work without resorting to multiple cond statements? The problem with cond is that I would have to specifically write down all the possible combinations of arguments used, which is ok for 3 arguments but it makes it very hard to extend if in the future I would like to use other keywords for filtering.
Common Lisp's keyword parameters have a special syntax that lets you tell
whether a parameter was supplied or not. I think you should be able to use
this to accomplish what you want.
Here is a working example, albeit with a slightly different data representation
since I don't have your definitions of local-time and get-record-date. You
should be able to easily adapt this to your code.
(defun my-filter-by (lst &key
(year nil year-p) ;; nil is the default
(month nil month-p) ;; year-p/month-p/day-p say whether
(day nil day-p)) ;; the argument was supplied
(remove-if-not
(lambda (element)
(let* ((year-okp (or (not year-p)
(equal year (cdr (assoc :year element)))))
(month-okp (or (not month-p)
(equal month (cdr (assoc :month element)))))
(day-okp (or (not day-p)
(equal day (cdr (assoc :day element)))))
(all-okp (and year-okp month-okp day-okp)))
all-okp))
lst))
And some examples:
(defparameter *lst* '(((:year . 2000) (:month . :may) (:day . 17))
((:year . 2000) (:month . :may) (:day . 18))
((:year . 2001) (:month . :aug) (:day . 2))
((:year . 2002) (:month . :jan) (:day . 5))))
(my-filter-by *lst*) ;; keeps everything
(my-filter-by *lst* :year 2000) ;; everything from 2000
(my-filter-by *lst* :year 2000 :day 17) ;; only 2000 / may 17

How to decode name of month into an integer

I'm trying to write a function that will let me choose (interactively) the month and year for org-agenda-month-view -- which uses a format of 201312 (without double-quotes) for December 2013 . I would like to use either words (December) or numbers (12) for the month, but need some assistance (please) to decode the name of the month into an integer -- something like (if (not (integer-p month)) (setq month (decode-name-of-month month))).
Also, any pointers on how to consolidate my two read-string  let bindings into just one action would be greatly appreciated -- i.e., be able to manually input January 2014 or 01 2014; instead of first inputting January and then inputting 2014 in two separate actions.
(let* (
(year (read-string "Insert the year: "))
(month (read-string "Insert the month: ")))
(org-agenda nil "1")
(org-agenda-month-view (read (format "%s%02s" year month))))
EDIT (December 11, 2013):  First working draft based upon the helpful answers by #Drew and #Sean Perry. Added variable org-agenda-start-day, which permits (org-agenda nil "1") to display [at the outset] the correct month based upon the user input -- the function org-agenda-month-view is no longer needed. Updated variable lawlist-parse-time-months to fix a typo and include additional possibilities -- e.g., 01, 02, etc.
(defvar lawlist-parse-time-months '(
("1" . "01")
("01" . "01")
("jan" . "01")
("january" . "01")
("2" . "02")
("02" . "02")
("feb" . "02")
("february". "02")
("3" . "03")
("03" . "03")
("mar" . "03")
("march" . "03")
("4" . "04")
("04" . "04")
("apr" . "04")
("april" . "04")
("5" . "05")
("05" . "05")
("may" . "05")
("6" . "06")
("06" . "06")
("jun" . "06")
("june" . "06")
("7" . "07")
("07" . "07")
("jul" . "07")
("july" . "07")
("8" . "08")
("08" . "08")
("aug" . "08")
("august" . "08")
("9" . "09")
("09" . "09")
("sep" . "09")
("september" . "09")
("10" . "10")
("oct" . "10")
("october" . "10")
("11" . "11")
("nov" . "11")
("november" . "11")
("12" . "12")
("dec" . "12")
("december" . "12")))
(defun encode-name-of-month (month_name)
(cdr (assoc (downcase month_name) lawlist-parse-time-months)) )
(defun decode-name-of-month (month)
(car (rassoc month lawlist-parse-time-months)))
(defun foo (month year)
(interactive
(let* ((mon+yr (split-string
(read-string "Month and year: " nil nil
(format-time-string "%B %Y"(current-time)))
nil 'TRIM))
(mon (car mon+yr))
(yr (cadr mon+yr))
(m2 (condition-case nil (format "%d" mon) (error nil))))
(list (or m2 mon) yr)))
(setq org-agenda-start-day (concat year "-" (encode-name-of-month month) "-" "01"))
(org-agenda nil "1") )
(require 'parse-time) ;; in standard lib
(defun encode-name-of-month (month_name)
(cdr (assoc (downcase month_name) parse-time-months))
)
(defun decode-name-of-month (month)
(car (rassoc month parse-time-months))
)
That should get you started.
(defun foo (month year)
(interactive
(let* ((mon+yr (split-string
(read-string "Month and year: " nil nil
(format-time-string "%B %Y"(current-time)))
nil 'TRIM))
(mon (car mon+yr))
(yr (cadr mon+yr))
(m2 (condition-case nil (format "%d" mon) (error nil))))
(list (or m2 mon) yr)))
(message "Month: %s, Year: %s" month year))
M-x foo 12 2013 ==> Month: 12, Year: 2013
M-x foo December 2013 ==> Month: December, Year: 2013
M-x foo Dec 2013 ==> Month: Dec, Year: 2013
M-x foo Nebraska 200000 ==> Month: Nebraska, Year: 200000
But you get the idea. (Check for valid month names and month & year numbers.)

Adding two alists by values in elisp

I have two lists of dotted-pairs of the form:
(((key1 . value1) . 5)
((key2 . value2) . 7))
(((key2 . value2) . 3)
((key3 . value3) . 9))
i want the result to be an association list:
(((key1 . value1) . 5)
((key2 . value2) . 10)
((key3 . value3) . 9))
How do i add two association lists by values in emacs lisp? In other words, if two alists have the same key, then values for that key should be added together in resulting alist.
The most probable answer for this is some elisp snippet, but i would also prefer a nifty emacs macro.
A solution using the CL module (written with readability rather than efficiency in mind):
(require 'cl)
(defun merge-alists (function default alist1 alist2)
(flet ((keys (alist) (mapcar #'car alist))
(lookup (key alist) (or (cdr (assoc key alist)) default)))
(loop with keys = (union (keys alist1) (keys alist2) :test 'equal)
for k in keys collect
(cons k (funcall function (lookup k alist1) (lookup k alist2))))))
You can use it like this:
elisp> (merge-alists '+ 0 '((foo . 1) (bar . 2)) '((foo . 11) (baz . 22)))
((baz . 22)
(foo . 12)
(bar . 2))
elisp> (merge-alists '* 1 '((foo . 1) (bar . 2)) '((foo . 11) (baz . 22)))
((baz . 22)
(foo . 11)
(bar . 2))
elisp> (merge-alists 'append '() '((foo a b) (bar c)) '((foo d e) (baz f g)))
((baz f g)
(foo a b d e)
(bar c))
elisp> (setq my-alist1 '(((key1 . value1) . 5) ((key2 . value2) . 7)))
(((key1 . value1) . 5)
((key2 . value2) . 7))
elisp> (setq my-alist2 '(((key2 . value2) . 3) ((key3 . value3) . 9)))
(((key2 . value2) . 3)
((key3 . value3) . 9))
elisp> (merge-alists '+ 0 my-alist1 my-alist2)
(((key3 . value3) . 9)
((key1 . value1) . 5)
((key2 . value2) . 10))
It could be something like:
(defun merge-alists (a1 a2)
(let ((ac (copy-alist a1)))
(dolist (x a2)
(when (null (assoc (car x) ac))
(add-to-list 'ac x)))
ac))
it will return copy of first list with data added from second list...
But if you'll use simple append function, then duplicates won't be found anyway, as functions usually return first found value, not all that exist.
Update: sorry, incorrectly read question, another answers do it correctly, and in more general way... Although, here is my variant of this function, without using CL package:
(defun merge-alists (a1 a2)
(let ((ac (copy-alist a1)))
(dolist (x a2)
(let ((r (assoc (car x) ac)))
(if (null r)
(add-to-list 'ac x)
(setf (cdr r) (+ (cdr x) (cdr r))))))
ac))
P.S. in your example, parentheses are unbalanced :-)

elegant way to count items

I have a list shaped like this:
'(("Alpha" . 1538)
("Beta" . 8036)
("Gamma" . 8990)
("Beta" . 10052)
("Alpha" . 12837)
("Beta" . 13634)
("Beta" . 14977)
("Beta" . 15719)
("Alpha" . 17075)
("Rho" . 18949)
("Gamma" . 21118)
("Gamma" . 26923)
("Alpha" . 31609))
How can I count the total number of occurrences of the terms in the car of each element in the list? Basically I want:
(("Alpha" . 4)
("Beta" . 5)
("Gamma" . 3)
("Rho" . 1))
No, this is not homework. I just don't have the "thinking in Lisp" thing quite yet.
In C#, I would use LINQ to do this. I can do it in lisp, too, using while loops and such but the way I am thinking of doing it seems overly complicated.
EDIT
This is what I have:
(defun count-uniq (list)
"Returns an alist, each item is a cons cell where the car is
a unique element of LIST, and the cdr is the number of occurrences of that
unique element in the list. "
(flet ((helper (list new)
(if (null list)
new
(let ((elt (assoc (car list) new)))
(helper (cdr list)
(if elt
(progn (incf (cdr elt)) new)
(cons (cons (car list) 1) new)))))))
(nreverse (helper list nil))))
(defun freqs (list &optional test key)
(let ((h (make-hash-table :test test)))
(dolist (x list)
(let ((key (if key (funcall key x) x)))
(puthash key (1+ (gethash key h 0)) h)))
(let ((r nil))
(maphash #'(lambda (k v) (push (cons k v) r)) h)
(sort r #'(lambda (x y) (< (cdr x) (cdr y)))))))
(freqs '(("Alpha" . 1538)
("Beta" . 8036)
("Gamma" . 8990)
("Beta" . 10052)
("Alpha" . 12837)
("Beta" . 13634)
("Beta" . 14977)
("Beta" . 15719)
("Alpha" . 17075)
("Rho" . 18949)
("Gamma" . 21118)
("Gamma" . 26923)
("Alpha" . 31609))
#'equal #'car)
Combining higher level Common Lisp functions:
(defun count-unique (alist)
(mapcar
(lambda (item)
(cons (car item)
(count (car item) alist :test #'equal :key #'car)))
(remove-duplicates alist :test #'equal :key #'car)))
It doesn't scale to large lists though. If you need O(n) performance use a hash table based solution instead, such as the less elegant:
(defun count-unique (alist)
(loop
with hash = (make-hash-table :test #'equal)
for (key . nil) in alist
do (incf (gethash key hash 0))
finally (return
(loop for key being each hash-key of hash
using (hash-value value)
collect (cons key value)))))
I dunno that this is the most elegant, but it seems reasonable:
(defun add-for-cheeso (data)
(let (result)
(dolist (elt data result)
(let ((sofar (assoc (car elt) result)))
(if sofar
(setcdr sofar (1+ (cdr sofar)))
(push (cons (car elt) 1) result))))))
Using Common Lisp extensions:
(require 'cl)
(loop with result = nil
for (key . dummy) in original-list
do (incf (cdr (or (assoc key result)
(first (push (cons key 0) result)))))
finally return (sort result
(lambda (a b) (string< (car a) (car b)))))
You can just say finally return result if you don't care about sorting the final result.
Every time you want to traverse a list and return some value afterwards, be it a new list or some aggregate result, you are thinking of a fold, also called "reduce" in Python and Lisps. Fold is a great abstraction, as it allows to write generic code, applicable for many use-cases just by tweaking some elements. What is similar between finding a sum of several numbers, finding a product, finding a minimum integer? They are all folds, because you run through the list and then return some result based on its content. In Emacs Lisp they would look like this:
(reduce '+ '(1 2 3 4 5)) ; 15
(reduce '* '(1 2 3 4 5)) ; 120
(reduce 'min '(1 2 3 4 5)) ; 1
But folds are even more general than this. What is similar between finding a sum, counting a number of even numbers in a list, removing every odd number, and building a list with every number increased by 5? Every such function can be implemented by taking some base value, successively transform it, until you get the result. You take this base value, metaphorical blob of clay, call it "accumulator", then take one element from a list and based on this element do something to this blob of clay, make it a draft of a magnificent sculpture. Then you take the next element from a list and do something new to your sculpture. You repeat that until the list is empty and you end up with a masterpiece. It's as if every element of a list is a single instruction in a large recipe. Just bear in mind, that you are completely free to do anything with the clay, you don't have to use the list elements in the result directly—technically, this means that the accumulator (and, thus, the result) may be of different type.
(reduce '+ '(1 2 3 4 5) :initial-value 0) ; 15
(reduce (lambda (acc x) (if (evenp x) (1+ acc) acc)) '(1 2 3 4 5) :initial-value 0) ; 2
(reduce (lambda (x acc) (if (oddp x) acc (cons x acc))) '(1 2 3 4 5) :initial-value '() :from-end t) ; (2 4)
(reduce (lambda (x acc) (cons (+ x 5) acc)) '(1 2 3 4 5) :initial-value '() :from-end t) ; (6 7 8 9 10)
Note about reducing from end: lists in Lisps are not smart arrays like in Python or Java, they are linked lists, therefore accessing or changing an element somewhere in a list is an O(n) operation, while "consing" to the beginning of a list is O(1). In other words, appending an element to the end of a list is expensive, therefore Lispers usually add elements to the beginning of a list and then finally reverse the list, which is called push/nreverse idiom. If we did the ordinary reduce in the last 2 functions, we would cons 1 to the accumulator and get (1), then cons 2 to accumulator and get (2 1), until we get the correct result but upside-down. We could use reverse function afterwards, but luckily Emacs's reduce supports :from-end keyword argument, so it conses 5, then 4, then 3, and so on.
It's clear now, that your operation is a fold, traverse the original alist and count occurrences of each key. Before writing our fold, let's talk about alists first. Alist in Lisp is a poor man's hash-table. You don't usually tinker with a programming language's hash-table implementation details, do you? You work with an API. In Python this API looks like square bracket syntax (d['a'] = 1) and dict methods (d.keys()). For alists API contains function assoc, which returns an item provided a key.
(assoc 'a '((a . 1) (b . 2))) ; (a . 1)
Why do I talk about implementation details? Because you work via assoc and you don't care how exactly this alist looks like, you abstract that away. Another piece of API is that if you want to add a new element or change an existing one, you simply cons a dotted pair to the alist. It's how you supposed to work with alists, regardless of their internal structure. Why does that work? For example, if I want to change value for key a to 10, I would simply run (cons '(a . 10) my-alist), and my-alist would end up being '((a . 10) (a . 1) (b . 2)). But it's no problem, because assoc returns only the first dotted pair and ignores the rest, so you can treat alist just like any other key-value data structure. With that in mind let's write our first serious fold.
(reduce (lambda (acc x)
(let* ((key (car x))
(pair (assoc key acc))
(count (cdr pair)))
(if pair
(cons (cons key (1+ count)) acc)
(cons (cons key 1) acc))))
my-alist
:initial-value '())
What happens here? We take your data and an empty list, which will soon become our desired result. At each step we take a pair from data and ask: does our result contain info about this pair? If not, then we add it to the result and put 1—we met this key for the first time. However, if we do find info about this pair in our result, then we must again add it to our result, but this time with a number increased by 1. Repeat that process for every item in your data, and you get:
(("Alpha" . 4) ("Gamma" . 3) ("Gamma" . 2) ("Rho" . 1) ("Alpha" . 3)
("Beta" . 5) ("Beta" . 4) ("Beta" . 3) ("Alpha" . 2) ("Beta" . 2)
("Gamma" . 1) ("Beta" . 1) ("Alpha" . 1))
Remember that assoc only cares about the first occurrence of a key? This alist would behave the same as if it was just (("Alpha" . 4) ("Gamma" . 3) ("Rho" . 1) ("Beta" . 5)), so we're good here. Still, could we change our fold as to get the latter, shorter result instead? Hold on, what's the need to over-complicate our fold, if we could just tweak the result afterwards? After all, what is computer programming, if not series of data transformations? There is no reason why you couldn't just remove all the "obsolete" pairs from your alist, just use cl-remove-duplicates with correct arguments, and you're done.
So we're proud of ourselves, we wrote a fold, a pillar of functional programming, yet careful examination exposes an inefficiency: we traverse the accumulator with assoc to find a pair and its value to increment. assoc takes O(n), reduce itself takes O(n), therefore our algorithm is O(n²) (read about order of growth, if you don't understand Big-O notation). It's clear that we should better work with a proper optimized hash-table instead, and convert it to an alist when we need. Rewrite our fold:
(reduce (lambda (acc x)
(cl-incf (gethash (car x) acc 0))
acc)
my-alist
:initial-value (make-hash-table :test 'equal))
(gethash k d 0) is equivalent to Python's d.get('k', 0), where the last argument is default. cl-incf (Common Lisp equivalent incf) is a smart macro that increments its argument in-place (read about setf to understand smart assignments). make-hash-table requires custom test function, because strings can't be compared with default eql function. To get an alist, just convert the result hash-table of our fold with ht->alist function, that we either take from Wilfred's ht.el library, or write ourselves:
(defun ht->alist (table)
(let (alist)
(maphash (lambda (k v)
(push (cons k v) alist))
table)
alist))
(require 'cl)
(defun count-uniq (list)
(let ((k 1) (list (sort (mapcar #'car list) #'string<)))
(loop for (i . j) on list
when (string= i (car j)) do (incf k)
else collect (cons i k) and do (setf k 1))))
Using high-order functions sort and reduce.
First sorting (using string<) then reducing (counting consecutive string= values in cons cells):
(reduce (lambda (r e)
(if (and r (string= (caar r) e))
(cons
(cons (caar r) (1+ (cdar r)))
(cdr r))
(cons (cons e 1) r)))
(sort (mapcar 'car alist) 'string<)
:initial-value nil)
This is pretty easy and very straightforward using the dash library:
(require 'dash)
(-frequencies (mapcar #'car my-list))
-frequencies was introduced in v2.20.0.
Here's what I think is an elegant functional solution using Emacs' alist functions, yielding a reusable frequencies function similar to Eli's answer:
(defun frequencies (vals)
(reduce
(lambda (freqs key)
(cons (cons key (+ 1 (or (cdr (assoc key freqs)) 0)))
(assq-delete-all-with-test key freqs 'equal)))
vals
:initial-value nil)))
(frequencies (mapcar 'car
'(("Alpha" . 1538)
("Beta" . 8036)
("Gamma" . 8990)
("Beta" . 10052)
("Alpha" . 12837)
("Beta" . 13634)
("Beta" . 14977)
("Beta" . 15719)
("Alpha" . 17075)
("Rho" . 18949)
("Gamma" . 21118)
("Gamma" . 26923)
("Alpha" . 31609))))
=> (("Alpha" . 4) ("Gamma" . 3) ("Rho" . 1) ("Beta" . 5))
Thanks to the support of cl-incf for alist-get:
;; (require 'cl-lib)
(defun simple-count (seq)
"Count each unique element in SEQ."
(let (counts)
(dolist (element seq)
(cl-incf (alist-get element counts 0 nil 'equal)))
counts))
Example:
(let ((data '(("Alpha" . 1538)
("Beta" . 8036)
("Gamma" . 8990)
("Beta" . 10052)
("Alpha" . 12837)
("Beta" . 13634)
("Beta" . 14977)
("Beta" . 15719)
("Alpha" . 17075)
("Rho" . 18949)
("Gamma" . 21118)
("Gamma" . 26923)
("Alpha" . 31609))))
(simple-count (mapcar 'car data)))
=> (("Rho" . 1) ("Gamma" . 3) ("Beta" . 5) ("Alpha" . 4))