Racket/Personreg
Från Täpp-Anders
Hoppa till navigeringHoppa till sök
#lang racket
;;;;;
;; Enkel personinfodatabas implementerad i Racket
;; Täpp-Anders Sikvall 2026-04-03 anders@sikvall.se
;;;;;
;; Global lista som håller alla personer, just nu tom
(define personer '())
;; Skapa en person med namngivna parametrar
(define (skapa-person
#:förnamn förnamn
#:efternamn efternamn
#:ålder ålder
#:stad [stad ""] ;Valfria parametrar med defaultvärden
#:telefon [telefon ""])
(define person (list (cons 'förnamn förnamn) ;när man consar par såhär
(cons 'efternamn efternamn) ;måste man använda car/cdr!
(cons 'ålder ålder)
(cons 'stad stad)
(cons 'telefon telefon)))
(set! personer (cons person personer)) ; lägger till en person i listan personer och returnerar
person) ; sedan samma person
;; Sökfunktion (oförändrad)
(define hitta-person
(make-keyword-procedure
(lambda (keywords keyword-values . rest)
(if (empty? keywords)
personer
(filter (λ (person)
(for/and ([kw keywords]
[val keyword-values])
(let ([field-key (string->symbol (keyword->string kw))])
(let ([found (assoc field-key person)])
(and found
(equal? (string-downcase (format "~a" val))
(string-downcase (format "~a" (cdr found)))))))))
personer)))))
;; Pretty-print funktioner
(define (pretty-print-person person)
(printf " Förnamn: ~a\n" (cdr (assoc 'förnamn person))) ;här går det inte använda rest
(printf " Efternamn: ~a\n" (cdr (assoc 'efternamn person))) ;för det är inte en lista, det
(printf " Ålder: ~a\n" (cdr (assoc 'ålder person))) ;är ett consat par (ålder . 34)
(let ([stad (cdr (assoc 'stad person))])
(when (and stad (not (equal? stad "")))
(printf " Stad: ~a\n" stad)))
(let ([telefon (cdr (assoc 'telefon person))])
(when (and telefon (not (equal? telefon "")))
(printf " Telefon: ~a\n" telefon)))
(newline))
(define (pretty-print-persons lst)
(if (empty? lst)
(displayln " Inga personer hittades.")
(for ([p (reverse lst)])
(pretty-print-person p))))
;; Spara och ladda – Lispformat (.dat)
(define data-fil "personer.dat") ;default filnamn
(define (spara-personer [filnamn data-fil]) ;men i anrop kan du ge eget namn
(with-output-to-file filnamn
(λ () (write personer))
#:exists 'replace) ;om filen finns, skriv över den
(printf "* Sparat ~a personer till \"~a\"\n"
(length personer) filnamn))
(define (ladda-personer [filnamn data-fil])
(if (file-exists? filnamn)
(begin
(set! personer (with-input-from-file filnamn read))
(printf "* Laddat ~a personer från \"~a\"\n" (length personer) filnamn))
(printf "! Filen \"~a\" finns inte.\n" filnamn)))
;; Spara och ladda – CSV-format (för enkel redigering)
(require csv-writing csv-reading)
(define csv-fil "personer.csv")
;; Hjälpfunktion: person → CSV-rad
(define (person->csv-row person)
(list (format "~a" (cdr (assoc 'förnamn person)))
(format "~a" (cdr (assoc 'efternamn person)))
(format "~a" (cdr (assoc 'ålder person)))
(format "~a" (cdr (assoc 'stad person)))
(format "~a" (cdr (assoc 'telefon person)))))
;; SPARA till CSV
(define (spara-personer-csv [filnamn csv-fil])
(define rubriker (list (list "Förnamn" "Efternamn" "Ålder" "Stad" "Telefon")))
(define rader (map person->csv-row (reverse personer))) ; reverse så ordningen blir "naturlig"
(with-output-to-file filnamn #:exists 'replace
(λ ()
(display-table rubriker)
(display-table rader)))
(printf "* Sparat ~a personer till CSV-filen \"~a\"\n" (length personer) filnamn))
;; LADDA från CSV
(define (ladda-personer-csv [filnamn csv-fil])
(if (file-exists? filnamn)
(let* ([reader (make-csv-reader (open-input-file filnamn))]
[all-rows (csv->list reader)] ;konvertera från csv till Lisp lista
[data-rows (if (empty? all-rows) '() (rest all-rows))]) ; hoppa över rubrik-rad
(define nya-personer
(for/list ([row data-rows])
(list (cons 'förnamn (list-ref row 0))
(cons 'efternamn (list-ref row 1))
(cons 'ålder (list-ref row 2)) ; behåll som sträng eller konvertera
(cons 'stad (list-ref row 3)) ; med string->number om du vill
(cons 'telefon (list-ref row 4)))))
(set! personer (append nya-personer personer)) ; eller (set! personer nya-personer) om du vill ersätta
(printf "* Laddat ~a personer från CSV-filen \"~a\"\n" (length nya-personer) filnamn))
(printf "! CSV-filen \"~a\" finns inte.\n" filnamn)))
;; SORTERA PERSONER
;; Sorterar först på efternamn över hela listan
;; därefter på efternamn. Då blir det som det ska
(define (sortera-personer)
;; Steg 1: Sortera på förnamn
(set! personer
(sort personer
(λ (p1 p2)
(string-ci<? (cdr (assoc 'förnamn p1)) ;string-ci är "string case insensitive"
(cdr (assoc 'förnamn p2))))))
;; Steg 2: Sortera på efternamn (detta blir den slutgiltiga ordningen)
(set! personer
(sort personer
(λ (p1 p2)
(string-ci<? (cdr (assoc 'efternamn p1))
(cdr (assoc 'efternamn p2))))))
personer) ; returnerar den sorterade listan (bra för kedjad användning)
;; ================================================================
;; Exempel på användning
;; ================================================================
;; Skapa testpersoner, detta behöver vi bara göra en gång för sedan skrivs den till disk och
;; vi behöver därefter bara hämta den vid behov!
(skapa-person #:förnamn "Anna" #:efternamn "Andersson" #:ålder 34 #:stad "Stockholm" #:telefon "070-123 45 67")
(skapa-person #:förnamn "Rickard" #:efternamn "Nilsson" #:ålder 28 #:stad "Kista")
(skapa-person #:förnamn "Enar" #:efternamn "Nilsson" #:ålder "74" #:stad "Färjestaden")
(skapa-person #:förnamn "Anna" #:efternamn "Svensson" #:ålder 45 #:stad "Malmö")
(skapa-person #:förnamn "Johan" #:efternamn "Larsson" #:ålder 31 #:stad "Stockholm")
(sortera-personer)
(spara-personer-csv "personlista.csv")
(displayln "=== Personer efter skapande ===")
(pretty-print-persons (hitta-person))
;; Spara både binärt och CSV
(displayln "\n=== Sparar till disk (både .dat och .csv) ===")
(spara-personer "personlista.dat")
(spara-personer-csv "personlista.csv")
;; Rensa minnet (simulerar omstart)
(set! personer '())
(displayln "\n=== Listan rensad ===")
(pretty-print-persons (hitta-person))
;; Ladda tillbaka
(displayln "\n=== Laddar från Lispdata ===")
(ladda-personer "personlista.dat")
(pretty-print-persons (hitta-person))
(set! personer '()) ; Nolla listan igen
(ladda-personer-csv "personlista.csv")
(displayln "\n=== Personer efter laddning från CSV ===")
(pretty-print-persons (hitta-person))
;; Exempel på sökning efter laddning
(displayln "\n=== Sök efter laddning (förnamn anna) ===")
(pretty-print-persons (hitta-person #:förnamn "anna"))