RosettaCodeData/Task/CSV-data-manipulation/Common-Lisp/csv-data-manipulation.lisp

40 lines
1.7 KiB
Common Lisp

(defun csvfile-to-nested-list (filename delim-char)
"Reads the csv to a nested list, where each sublist represents a line."
(with-open-file (input filename)
(loop :for line := (read-line input nil) :while line
:collect (read-from-string
(substitute #\SPACE delim-char
(format nil "(~a)~%" line))))))
(defun sublist-sum-list (nested-list)
"Return a list with the sum of each list of numbers in a nested list."
(mapcar (lambda (l) (if (every #'numberp l)
(reduce #'+ l) nil))
nested-list))
(defun append-each-sublist (nested-list1 nested-list2)
"Horizontally append the sublists in two nested lists. Used to add columns."
(mapcar #'append nested-list1 nested-list2))
(defun nested-list-to-csv (nested-list delim-string)
"Converts the nested list back into a csv-formatted string."
(format nil (concatenate 'string "~{~{~2,'0d" delim-string "~}~%~}")
nested-list))
(defun main ()
(let* ((csvfile-path #p"projekte/common-lisp/example_comma_csv.txt")
(result-path #p"results.txt")
(data-list (csvfile-to-nested-list csvfile-path #\,))
(list-of-sums (sublist-sum-list data-list))
(result-header "C1,C2,C3,C4,C5,SUM"))
(setf data-list ; add list of sums as additional column
(rest ; remove old header
(append-each-sublist data-list
(mapcar #'list list-of-sums))))
;; write to output-file
(with-open-file (output result-path :direction :output :if-exists :supersede)
(format output "~a~%~a"
result-header (nested-list-to-csv data-list ",")))))
(main)