For a hobby project I deal with lists of a-lists like
((0 . 0) (0 . 1) (0 . 3) (0 . 4) (0 . 7) (0 . 8))
where the list could have up to nine elements and the a-lists consists of just integers from 0 to 9. I want to split the list into the sub-units with consecutive cdrs.
(((0 . 0) (0 . 1)) ((0 . 3) (0 . 4)) ((0 . 7) (0 . 8)))
A sub-unit can have just one element and the list can have no sub-unit at all, like:
((0 . 0) (0 . 1) (0 . 2) (0 . 4)) or
((0 . 0) (0 . 1) (0 . 2) (0 . 3) (0 . 4))
The results should be:
(((0 . 0) (0 . 1)) ((0 . 3) (0 . 4)) ((0 . 7) (0 . 8)))
(((0 . 0) (0 . 1) (0 . 2)) ((0 . 4)))
(((0 . 0) (0 . 1) (0 . 2) (0 . 3) (0 . 4)))
Using iterate I came up with a two-step approach. First, scan the list and check whether there are sub-units or not, returning the positions of the gaps. And second, split the list apart using a function split-at I implemented before:
(defun split-at (count original-list)
(unless (or (null original-list) (minusp count)
(>= count (length original-list)))
(list (subseq original-list 0 count)
(subseq original-list count))))
(defun sub-units (units)
"Scan UNITS for sub-units."
(iter
(for (a . b) in units)
(for last-b previous b initially -1)
(for pos from 0)
(unless (= 1 (- b last-b))
(collecting pos))))
(defun split-sub-units (units)
"Splits UNITS into its sub-units."
(iter
(with pos = (or (sub-units units) (list 0)))
(for p in pos)
(for last-p previous p)
(for (head tail) first (split-at p units) then (split-at last-p tail))
(when head
(collect head into result))
(finally (return (nconc result (list tail))))))
Is it possible to merge the two functions sub-units and split-sub-units into one? Does it make any difference regarding style or efficiency?
I think the problem can be solved by iterating in the following way: collect all the elements in a list until their cdr are consecutive, and then repeat the previous process until the original list is empty, collecting all the produced lists. This can be done iteratively, with the total cost of O(n) where n is the length of the original list.
I use loop instead of iterate because I am more familiar with the first construct, it should be simple to convert it to iterate.
(defun split (l)
(loop for (a b) = (loop for (x . y) on l
collect x into a
when (and y (/= (cdar y) (1+ (cdr x))))
do (return (list a y)) ; split here
finally (return (list a nil))) ; never split
collect a ; a list has been produced, collect it
while b ; if there are other elements
do (setf l b))) ; repeat splitting over them
A few tests:
CL-USER> (split '((0 . 0) (0 . 1) (0 . 2)))
(((0 . 0) (0 . 1) (0 . 2)))
CL-USER> (split '((0 . 0) (0 . 1) (0 . 3) (0 . 4) (0 . 7) (0 . 8)))
(((0 . 0) (0 . 1)) ((0 . 3) (0 . 4)) ((0 . 7) (0 . 8)))
CL-USER> (split '((0 . 0)))
(((0 . 0)))
CL-USER> (split '())
(NIL)
Related
Still new to Scheme, and I'm currently having trouble with the creation of a list of pairs constructed from two separate lists of different lengths.
Here is my current code:
#lang racket
(define letters '(a b c))
(define (create-lst-letters lst)
(map (lambda (x y) (list x y)) letters lst))
Console input:
(create-lst-letters '(1 2 3 4 5 6 7 8))
Current output:
map: all lists must have same size
first list length: 8
other list length: 3
Wanted output:
'((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
Another intuition would be to get the quotient and remainder of the length of the input list divided by "letters". Make a new list by appending "letters" quotient times, and then concatenating the first remainder number of elements of "letters". With that new list perform a map as above. I don't feel this is good practice nor an elegant solution, but I'm out of other ideas.
You can use in-cycle and for/list to concisely produce the output that you want.
#lang racket
(define letters '(a b c))
(define (create-lst-letters lst)
(for/list ([x (in-cycle letters)] [y lst])
(cons x y)))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; '((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
A pure Scheme version:
#!r7rs
(import (scheme base)
(scheme list))
(define create-lst-letters
(let ((letters (circular-list 'a 'b 'c)))
(lambda (lst)
(map cons letters lst))))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; ==> ((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
I use Racket and it doesn't have a Red edition of R7RS yet, but thsi can easily be rewritten to R6RS using SRFI-1 (same as (scheme list))
#!r6rs
(import (except (rnrs base) map)
(only (srfi :1) map circular-list))
(define create-lst-letters
(let ((letters (circular-list 'a 'b 'c)))
(lambda (lst)
(map cons letters lst))))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; ==> ((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
And of course if you don't like writing Scheme code you can write almost the same using #lang racket language.
#lang racket
(require srfi/1)
(define create-lst-letters
(let ((letters (circular-list 'a 'b 'c)))
(lambda (lst)
(map cons letters lst))))
(create-lst-letters '(1 2 3 4 5 6 7 8))
; ==> ((a . 1) (b . 2) (c . 3) (a . 4) (b . 5) (c . 6) (a . 7) (b . 8))
I'm learning Lisp. I wish to add a new list to a list of list, say ((1 1 1) (0 0 0)), where the new head of this list collection is computed based on the previous head.
Here's what I tried, in the REPL environment in Slimv with sbcl:
> (defvar *ll* (list (list 1 1 1) (list 0 0 0)))
*LL*
> *ll*
((1 1 1) (0 0 0))
> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *ll*)) 2)
2
> *ll*
((1 1 2) (1 1 2) (0 0 0))
As shown above, I only wanted to modify the last element of the first list, but somehow the last element of the second list was also changed.
I noticed that if instead I push into a brand-new list, then the result is different:
> (defvar *lll* (list (list 1 1 1) (list 0 0 0)))
*LLL*
> (push '(1 1 1) *lll*)
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *lll*)) 2)
2
> *lll*
((1 1 2) (1 1 1) (0 0 0))
I'd like to know what causes these different results, and how to achieve the result that "adds a new list to the list of list, where the new head of resulting list collection is computed based on the previous head." Thanks!
(car *ll*) and (cadr *ll*) are the same list
> (defvar *ll* (list (list 1 1 1) (list 0 0 0)))
*LL*
> *ll*
((1 1 1) (0 0 0))
> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *ll*)) 2)
2
> *ll*
((1 1 2) (1 1 2) (0 0 0))
As shown above, I only wanted to modify the last element of the first
list, but somehow the last element of the second list was also
changed.
There's only one object there, and you modified it. It's not really any different than if you had some sort of structured data type (and really, what is a cons cell but a structured datatype with just two fields). If you have a list of people, and then you add the first person to the list again, there's still just one person; the person just appears two places in the list. If you change the name of the person, you'll see it in both places. You can actually see the shared structure if you set *print-circle* to t.
CL-USER> (defvar *ll* (list (list 1 1 1) (list 0 0 0)))
*LL*
CL-USER> *ll*
((1 1 1) (0 0 0))
CL-USER> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
CL-USER> *ll*
((1 1 1) (1 1 1) (0 0 0))
CL-USER> (setf *print-circle* t)
T
CL-USER> *ll*
(#1=(1 1 1) #1# (0 0 0))
The notation using #1=… and #1# indicates that the same object is the first and second element of the list.
If you want a copy, make a copy
I wish to add a new list to a list of list, say ((1 1 1) (0 0 0)),
where the new head of this list collection is computed based on the
previous head. …
> (push (car *ll*) *ll*)
((1 1 1) (1 1 1) (0 0 0))
You said that you wanted to add a new list to a list of lists, but you're not adding a new list; you're adding (car *ll*) which is the list you created at the beginning with (list 1 1 1). If you want to copy the list, you'll need to copy it explicitly, e.g., with copy-list:
> (push (copy-list (car *ll*)) *ll*)
((1 1 1) (1 1 1) (0 0 0))
Don't modify literal data!
As an aside, what you're doing in your second code block is actually undefined behavior, since you're modifying the literal list '(1 1 1).
> (defvar *lll* (list (list 1 1 1) (list 0 0 0)))
*LLL*
> (push '(1 1 1) *lll*) ; '(1 1 1) is literal data.
((1 1 1) (1 1 1) (0 0 0))
> (setf (nth 2 (car *lll*)) 2) ; (car *lll*) is literal data, and you're modifying it!
2
> *lll*
((1 1 2) (1 1 1) (0 0 0))
See my answer to Unexpected persistence of data for more about why this can be problematic.
I'm using this code to make sure the lists are put together so it will work with another function I'm writing.
#lang racket
(define path_from_start null)
(define path_stack null)
(define input1 '(0 0))
(define input2 '(1 2))
(define input3 '(3 1))
(define (test xy)
(set! path_from_start (append path_from_start (list xy)))
(display "path from start:") (display path_from_start)
(display "\n")
(set! path_stack (list path_from_start path_stack))
(display "path_stack")(display path_stack)
(display "\n")
;(set! path_stack (cdr path_stack))
;(display path_stack)
;(display "\n")
)
(test input1)
(test input2)
(test input3)
But I'm getting this output:
path from start:((0 0))
path_stack(((0 0)) ())
path from start:((0 0) (1 2))
path_stack(((0 0) (1 2)) (((0 0)) ()))
path from start:((0 0) (1 2) (3 1))
path_stack(((0 0) (1 2) (3 1)) (((0 0) (1 2)) (((0 0)) ())))
1st item on path_stack: '((0 0) (1 2) (3 1))
I don't want the empty list at the end of path_stack. It doesn't show in path_from_start. Its probably because of the way I'm forming path_stack. But I want the preserve the bracket formats I have now. Is there another variable I can initialize path_stack to?
I've looked up other methods, but they all break the bracket format. Should I use one of those methods right at the first step? Nip it at the bud with only 1 other element in list so I can easily reform that?
Thanks.
Try this, in the second set! use list* instead of list:
(set! path_stack (list* path_from_start path_stack))
Here's the result, I believe this fixes the issues with the brackets - the sample output in the question doesn't seem correct:
path from start: ((0 0))
path_stack: (((0 0)))
path from start: ((0 0) (1 2))
path_stack: (((0 0) (1 2)) ((0 0)))
path from start: ((0 0) (1 2) (3 1))
path_stack: (((0 0) (1 2) (3 1)) ((0 0) (1 2)) ((0 0)))
Now we can retrace each step in the path, like this:
(first path_stack)
=> '((0 0) (1 2) (3 1))
(second path_stack)
=> '((0 0) (1 2))
(third path_stack)
=> '((0 0))
I'm trying to write a function in Common Lisp that deletes an item from a list. Here's what I've written so far:
(defun aux-remove-fio (lst toremove)
(if (equal (first lst) toremove)
(pop lst)
(aux-remove-fio (rest lst) toremove))))
When I test the function, here's the result:
CG-USER(49): a3
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
CG-USER(50): (pop a3)
(1 (1 . 1) (1 . 2))
CG-USER(51): a3
((2 (2 . 1) (1 . 2)))
CG-USER(52): (setf a3 '((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2))))
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
CG-USER(53): (aux-remove-fio a3 '(1 (1 . 1) (1 . 2)))
(1 (1 . 1) (1 . 2))
CG-USER(54): a3
((1 (1 . 1) (1 . 2)) (2 (2 . 1) (1 . 2)))
Can anyone explain why my function isn't working?
Yes. Your function changes the value of its local variable, lst --- nothing more.
Here is a simpler example, showing the same thing:
(setq a3 '(1 2 3)) ; (1 2 3)
(defun foo (xs) (setq xs (cdr xs))) ; Change value of xs.
;; Change value of xs to (2 3). Its initial value is the value of a3, i.e., (1 2 3)
(foo a3)
a3 ; => (1 2 3)
After foo is called, a3 still points to the original cons cell whose car is 1 and whose cdr is the same cons cell as before, with car 2, etc. All you have done i smake local variable xs point to the cdr of the cons cell it originally pointed to, which was the same cons cell that a3 points to.
If you want your function to change the value of global variable a3, then do so directly:
(defun foo () (pop a3))
Or if you just want a function that pops the first element off of the list value of a special variable, then you have such a function: pop --- just use (pop a3).
If you want a function that changes the value of a global variable that you pass it, then pass the variable (i.e., symbol) and not its value:
(defun foo (var)
(let* ((val (symbol-value var))
(head (car val)))
(set var (cdr val))
head))
(foo 'a3) ; Pop off a3's head and return it.
a3 ; Now a3 has lost its head.
This definition of foo is like a simple form of pop, except that it is a function, so evaluates its argument.
This is my simple solution. I define a function in REPL
CL-USER> (defun remove-element (mylist n)
(append
(subseq mylist 0 n)
(subseq mylist (1+ n))))
then run it (errors on your Lisp implementation may differ)
CL-USER> (remove-element '(1 2 3 4 5) 0)
(2 3 4 5)
CL-USER> (remove-element '(1 2 3 4 5) 1)
(1 3 4 5)
CL-USER> (remove-element '(1 2 3 4 5) 5)
; Evaluation aborted on #<SB-KERNEL:BOUNDING-INDICES-BAD-ERROR ...
CL-USER> (remove-element '(1 2 3 4 5) -1)
; Evaluation aborted on #<TYPE-ERROR ...
does anyone know how to count all numbers or characters in list and print it in pair in this format: (number . number_of_occurrences). For example:
(count '(3 1 3 2 1 2 3 3 3))
((3 . 5) (1 . 2) (2 . 2))
(count '(d b a c b b a))
((d . 1) (b . 3) (a . 2) (c . 1))
Thanks in advance for helping me :)
Here's an idea - use a hash table to keep track of the number of occurrences. This is an O(n) procedure:
(define (counter lst)
(let ((counts (make-hash)))
(let loop ((lst lst))
(cond ((null? lst)
(hash->list counts))
(else
(hash-update! counts (car lst) add1
(lambda () 0))
(loop (cdr lst)))))))
Alternatively, here's a simpler version (it doesn't use filter) of #mobyte's solution in Scheme - noticing that this is O(n^2) and hence less efficient than the hash table-based procedure:
(define (counter lst)
(map (lambda (e)
(cons e (count (curry equal? e) lst)))
(remove-duplicates lst)))
Either way, It works as expected:
(counter '(3 1 3 2 1 2 3 3 3))
=> '((3 . 5) (2 . 2) (1 . 2))
(counter '(d b a c b b a))
=> '((b . 3) (a . 2) (d . 1) (c . 1))
This is solution in clojure. But I hope it'll be helpful:
(defn counter [l]
(map (fn [e]
[e (count (filter #{e} l))])
(distinct l)))
(counter [3 1 3 2 1 2 3 3 3])
-> ([3 5] [1 2] [2 2])
(counter '(d b a c b b a))
-> ([d 1] [b 3] [a 2] [c 1])