Skip to content

Commit

Permalink
add empty string check
Browse files Browse the repository at this point in the history
  • Loading branch information
kmarker1101 committed Jun 25, 2024
1 parent bb11561 commit e81e9d6
Showing 1 changed file with 49 additions and 56 deletions.
105 changes: 49 additions & 56 deletions exercises/practice/parallel-letter-frequency/.meta/example.el
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@
(require 'cl-lib)

(defun clean-text (text)
"Clean up the text by removing numbers, punctuation, and whitespace, but keeping alphabetic characters (including Unicode) and converting to lowercase."
(let ((cleaned-text (replace-regexp-in-string "[^[:alpha:]]" "" text)))
(downcase cleaned-text)))
"Clean TEXT by removing numbers, punctuation, and whitespace, keeping only alphabetic characters and converting to lowercase."
(downcase (replace-regexp-in-string "[^[:alpha:]]" "" text)))

(defun combine-frequencies (freqs-list)
"Combine a list of frequency hash tables into a single hash table."
"Combine a list of frequency hash tables in FREQU-list into a single hash table."
(let ((combined-freqs (make-hash-table :test 'equal)))
(dolist (freqs freqs-list)
(maphash (lambda (key value)
Expand All @@ -21,15 +20,15 @@
combined-freqs))

(defun serialize-hash-table (hash-table)
"Serialize a hash table to a string."
"Serialize HASH-TABLE to a string."
(let (result)
(maphash (lambda (key value)
(push (format "%c:%d" key value) result))
hash-table)
(string-join (reverse result) ",")))

(defun deserialize-hash-table (str)
"Deserialize a string to a hash table."
"Deserialize STR to a hash table."
(let ((hash-table (make-hash-table :test 'equal)))
(unless (string= str "") ; Check if the string is empty
(dolist (item (split-string str ","))
Expand All @@ -39,58 +38,52 @@
hash-table))))
hash-table))

(defun process-text-chunk (texts)
"Process a chunk of texts and return the serialized result."
(let ((cleaned-texts (mapcar #'clean-text texts)))
(if (every #'null cleaned-texts) ; Check if all cleaned texts are empty
'() ; Return nil (empty list)
(serialize-hash-table
(combine-frequencies
(mapcar 'count-frequencies cleaned-texts))))))

(defun calculate-frequencies (texts)
"Calculate letter frequencies for each string in TEXTS using processes."
(if (null texts) ; Check if the input list is empty
'() ; Return the empty list if so
(let* ((num-processes (min (length texts) (max 1 (string-to-number (shell-command-to-string "nproc")))))
(texts-per-process (ceiling (/ (float (length texts)) num-processes)))
(results (make-hash-table :test 'equal))
(pending num-processes)
(final-result nil)
(processes nil))
;; Create processes
(dotimes (i num-processes)
(let* ((process-texts (cl-subseq texts
(* i texts-per-process)
(min (* (1+ i) texts-per-process) (length texts))))
(cleaned-texts (mapcar #'clean-text process-texts))
(command (format "(princ (let ((freqs (make-hash-table :test 'equal))) (dolist (text '%S) (let ((text-freqs (make-hash-table :test 'equal))) (dolist (char (string-to-list text)) (puthash char (1+ (gethash char text-freqs 0)) text-freqs)) (maphash (lambda (key value) (puthash key (+ value (gethash key freqs 0)) freqs)) text-freqs))) (let (result) (maphash (lambda (key value) (push (format \"%%c:%%d\" key value) result)) freqs) (string-join (reverse result) \",\")))))"
cleaned-texts))
(process (make-process
:name (format "letter-freq-process-%d" i)
:buffer (generate-new-buffer (format " *letter-freq-process-%d*" i))
:command (list "emacs" "--batch" "--eval" command)
:sentinel (lambda (proc _event)
(when (eq (process-status proc) 'exit)
(with-current-buffer (process-buffer proc)
(let ((result (deserialize-hash-table (buffer-string))))
(maphash (lambda (key value)
(puthash key (+ value (gethash key results 0)) results))
result))
(setq pending (1- pending))
(when (= pending 0)
(setq final-result (combine-frequencies (list results)))
(let ((sorted-result nil))
(maphash (lambda (key value)
(push (list (char-to-string key) value) sorted-result))
final-result)
(setq sorted-result (sort sorted-result (lambda (a b) (string< (car a) (car b)))))
(setq final-result (apply 'append sorted-result))))))))))
(push process processes)))
;; Wait for all processes to finish
(while (> pending 0)
(sleep-for 0.1))
final-result)))
(let ((cleaned-texts (mapcar #'clean-text texts)))
(if (cl-every #'string-empty-p cleaned-texts)
'() ;; Return empty list if all cleaned texts are empty
(let* ((num-processes (min (length cleaned-texts) (max 1 (string-to-number (shell-command-to-string "nproc")))))
(texts-per-process (ceiling (/ (float (length cleaned-texts)) num-processes)))
(results (make-hash-table :test 'equal))
(pending num-processes)
(final-result nil)
(processes nil))
;; Create processes
(dotimes (i num-processes)
(let* ((start-index (* i texts-per-process))
(end-index (min (* (1+ i) texts-per-process) (length cleaned-texts)))
(process-texts (if (< start-index (length cleaned-texts))
(cl-subseq cleaned-texts start-index end-index)
'())))
(when (not (null process-texts))
(let* ((command (format "(princ (let ((freqs (make-hash-table :test 'equal))) (dolist (text '%S) (let ((text-freqs (make-hash-table :test 'equal))) (dolist (char (string-to-list text)) (when (string-match-p \"[[:alpha:]]\" (char-to-string char)) (puthash char (1+ (gethash char text-freqs 0)) text-freqs))) (maphash (lambda (key value) (puthash key (+ value (gethash key freqs 0)) freqs)) text-freqs))) (let (result) (maphash (lambda (key value) (push (format \"%%c:%%d\" key value) result)) freqs) (string-join (reverse result) \",\")))))"
process-texts))
(process (make-process
:name (format "letter-freq-process-%d" i)
:buffer (generate-new-buffer (format " *letter-freq-process-%d*" i))
:command (list "emacs" "--batch" "--eval" command)
:sentinel (lambda (proc _event)
(when (eq (process-status proc) 'exit)
(with-current-buffer (process-buffer proc)
(let ((result (deserialize-hash-table (buffer-string))))
(maphash (lambda (key value)
(puthash key (+ value (gethash key results 0)) results))
result))
(setq pending (1- pending))
(when (= pending 0)
(setq final-result (combine-frequencies (list results)))
(let ((sorted-result nil))
(maphash (lambda (key value)
(push (list (char-to-string key) value) sorted-result))
final-result)
(setq sorted-result (sort sorted-result (lambda (a b) (string< (car a) (car b)))))
(setq final-result (apply 'append sorted-result))))))))))
(push process processes)))))
;; Wait for all processes to finish
(while (> pending 0)
(sleep-for 0.1))
final-result))))

(provide 'parallel-letter-frequency)
;;; parallel-letter-frequency.el ends here

0 comments on commit e81e9d6

Please sign in to comment.