Reputation: 24535
I have a small text file as follows:
one, 50, 40, 65, 500
two, 80, 70, 100, 250
three, 100, 55, 125, 100
four, 50, 45, 58, 850
I am trying to read it and to make a list of all the values in 2nd column of each line. Following is the code I am using:
#lang racket
(define (testfn fname)
(let ((sl '() ) (list2 (list)) (templist '()) (ss "") )
(set! sl (file->lines fname))
(for ((line sl))
(set! templist (string-split line ","))
(println templist)
(set! ss (list-ref templist 1))
(println ss)
(append list2 ss) ; does not work
(append list2 (list ss)) ; does not work
(cons ss list2) ; does not work
(cons (list ss) list2) ; does not work
(cons list2 (list ss)) ; does not work
(cons list2 ss) ; does not work
(println list2)
)
(println list2)))
(testfn "test.txt")
However, the 'list2' is not getting appended with string 'ss' with any of the many methods that I am using above. The output shows it:
'("one" " 50" " 40" " 65" " 500")
" 50"
'()
'("two" " 80" " 70" " 100" " 250")
" 80"
'()
'("three" " 100" " 55" " 125" " 100")
" 100"
'()
'("four" " 50" " 45" " 58" " 850")
" 50"
'()
'()
>
Where is the problem and how can I solve it?
Edit: After correcting the mistake pointed out by @JohnClements , following code works:
#lang racket
(define (testfn fname)
(let ((sl '() ) (list2 (list)) (templist '()) (ss "") )
(set! sl (file->lines fname))
(for ((line sl))
(set! templist (string-split line ","))
(set! ss (list-ref templist 1))
(set! list2 (append list2 (list ss)))
(println list2)
)
(println list2)))
(testfn "test.txt")
Output:
'(" 50")
'(" 50" " 80")
'(" 50" " 80" " 100")
'(" 50" " 80" " 100" " 50")
'(" 50" " 80" " 100" " 50")
>
Upvotes: 0
Views: 810
Reputation: 17203
Yikes! Your code is written in a very imperative style. Code in this style is hard to read and maintain. I think you'll find that if you break your code into much smaller functions, and develop code according to the How To Design Programs design recipe (www.htdp.org), you'll wind up with something much cleaner.
One of the basic problems you're running into is an assumption that functions such as "append" cause mutation. Specifically, you're assuming that if you call, for instance, (append a b)
, that one or both of these lists will be different after the call. This is not the case.
To see why, imagine I wrote this code:
#lang racket
(define a 3)
(define b 6)
(+ a b)
(- b a)
(+ (* 2 a) b)
What would the values of a
and b
be, after running this code?
I think you'd probably expect them still to be 3 and 6. That's because addition
and subtraction don't mutate their arguments. The same thing is true of cons
and append
. So calling (append a b)
produces a new list, but if you don't use that value, then it won't go anywhere.
Here, let me write some code for you, very quickly...
EDIT:
Here's a program that returns the second element of each list, using an HtDP style:
#lang racket
(require rackunit)
;; given a list of lists, return the second of each list:
;; list-of-lists -> list
(define (second-element-map lol)
(cond [(empty? lol) empty]
[else (cons (second (first lol))
(second-element-map (rest lol)))]))
;; let's test it:
(check-equal? (second-element-map '((a b c) (d e f g) (1 2 3)))
'(b e 2))
;; given a list of lines, split each one into commas
(define (split-each-line lines)
(cond [(empty? lines) empty]
[else (cons (string-split (first lines) ",")
(split-each-line (rest lines)))]))
;; let's test it:
(check-equal? (split-each-line '("a,34,2987" "hn th, th"))
'(("a" "34" "2987")
("hn th" " th")))
;; given a filename, return a list containing the second element of
;; each list
;; path-string -> list
(define (testfn fname)
(second-element-map (split-each-line (file->lines fname))))
(testfn "/tmp/abc.txt")
Can it be shorter? Of course. The HtDP style is clean, and guaranteed to work.
... but here's how I'd write this program for personal consumption:
#lang racket
(define (testfn2 fname)
(for/list ([l (in-list (file->lines fname))])
(second (string-split l ","))))
(testfn2 "/tmp/abc.txt")
Upvotes: 4