given a list of the following form:
(define lst (list
(list
(make-route-section 32 'ordinary-road 23 0.45)
(make-route-section 54 'ordinary-road 92 0.83)
(make-route-section 14 'street 8 0.82)
(make-route-section 44 'ferry 34 0.64)
(make-route-section 96 'ferry 249 0.41)
)(
list
(make-route-section 92 'ordinary-road 12 0.44)
(make-route-section 98 'highway 45.243 0.3)
(make-route-section 44 'ordinary-road 34.4 0.64)
(make-route-section 39 'street 6 0.8)
)(
list
(make-route-section 62 'highway 82 0.35)
(make-route-section 58 'street 4 0.46)
(make-route-section 50 'highway 81 0.24)
(make-route-section 75 'highway 67.3 0.39)
)
)
A route section is the following:
(define-struct route-section (id kind length eco-index))
(define-struct traffic-jam (section-id delay))
How would I, for example filter out certain structs with given ids (first field of the struct) with a list like (list 32 62) and it would return me the second element of the outer list. What confused me especially is, when I entered (second lst) it returned the second element of the first list of the whole list.
How would I add up the lengths of the route sections? I feel so dumb, even using higher order functions I could't iterate through the nested list.
Here's how to sum the length of the route.
A route is a list of segments, each segment is a list of sections, which are structures.
To sum a list of numbers a good approach is (foldl + 0 <list>). But we don't have a list of numbers, we have a list of segments. So we want to get a number from each segment. We could use foldl again. But each element of the segment isn't a number: it's a section. So a good way of taking a list of somethings and getting a list of something-elses is to use (map <function-to-turn-something-into-something-else> <list-of-somethings>).
route-section-length will take a section object and return its length, so that's the function we want to map. So we could start, on a segment, to turn it into a list of lengths of its sections:
(map route-section-length <segment>)
And now we have a list of numbers for each segment, and we can use foldl:
(foldl + 0 (map route-section-length <segment>))
And this will turn a segment into a number. Well, we have a list of segments, so we want to turn them into a list of numbers, which we can do by mapping a function whose body is the expression above over the list:
(map (λ (segment)
(foldl + 0 (map route-section-length segment)))
route)
OK, that gives us a list of numbers, which we now need to add up, again using foldl:
(foldl + 0
(map (λ (segment)
(foldl + 0 (map route-section-lenght segment)))
route))
And that, wrapped in a definition, is what we want.
Also: indent your code properly.
Related
I have a bunch of text lines , iam drawing\showing them one in each line using entmake procedure. and for that i provide a insertion point , i want the text to be aligned from the left , the problem is that the lines lengths are different and the insertion point seems to be the center of text.
i was thinking of using the length of the text and the size\height of the text to calculate the pad i need to make so the text is aligned . if iam in the right path i cant find out how to do the calculation .
if I am not please help.
here is how i make text entities:
(defun text(point text)
(list ( cons 0 "TEXT")
(cons 11 point)
(cons 10 point)
(cons 40 0.4)
(cons 1 text)
(cons 41 1.0)
(cons 72 4)
(cons 73 0)
) )
thank you
You can create left-justified single-line TEXT entities using the following entmakex expression:
(defun mytext ( ins hgt str )
(entmakex
(list
'(000 . "TEXT")
(cons 010 ins)
(cons 040 hgt)
(cons 001 str)
)
)
)
Which may be called for example:
(mytext '(1.0 1.0 0.0) 0.4 "This is a test")
Here:
DXF group 0 is the entity type
DXF group 10 is the text insertion point
DXF group 40 is the text height
DXF group 1 is the text content
These four DXF groups are the minimum groups required to create a single-line TEXT entity.
For left-justified single-line text, only DXF group 10 is required to specify the position; for all other justifications, DXF group 11 represents the text alignment point and the value of DXF group 10 (the insertion point) is ignored if supplied (though, the group must be present).
For example, for middle-center justified single-line text, you might use the following:
(defun mytext ( ins hgt str )
(entmakex
(list
'(000 . "TEXT")
(cons 010 ins)
(cons 011 ins)
(cons 040 hgt)
(cons 001 str)
'(072 . 1)
'(073 . 2)
)
)
)
Here:
DXF group 0 is the entity type
DXF group 10 is the text insertion point (used if both DXF 72 and 73 are zero)
DXF group 11 is the text alignment point (used if either DXF 72 or 73 are non-zero)
DXF group 40 is the text height
DXF group 1 is the text content
DXF group 72 determines the horizontal alignment
DXF group 73 determines the vertical alignment
If you want to create single-line text which adheres to the properties of the active UCS (for example, created in the UCS construction plane, rotated to align with the UCS x-axis), you can use the following:
(defun mytext ( ins hgt str )
(
(lambda ( ocs )
(entmakex
(list
'(000 . "TEXT")
(cons 010 (trans ins 1 ocs))
(cons 050 (angle '(0.0 0.0) (trans (getvar 'ucsxdir) 0 ocs t)))
(cons 040 hgt)
(cons 001 str)
(cons 210 ocs)
)
)
)
(trans '(0.0 0.0 1.0) 1 0 t)
)
)
This assumes that the insertion point will be supplied relative to the active UCS, e.g.:
(defun c:test ( )
(mytext
(progn
(initget 1)
(getpoint "\nSpecify insertion point: ")
)
(progn
(initget 7)
(getdist "\nSpecify text height: ")
)
(getstring t "\nSpecify text content: ")
)
)
A reference for all of the DXF groups applicable to a TEXT entity may be found here.
I am looking for a function that parses integer lists in Emacs Lisp, along the lines of Perl's Set::IntSpan. I.e., I would like to be able to do something like this:
(parse-integer-list "1-3, 4, 8, 18-21")
⇒ (1 2 3 4 8 18 19 20 21)
Is there an elisp library somewhere for this?
The following does what you want:
(defun parse-integer-list (str)
"Parse string representing a range of integers into a list of integers."
(let (start ranges)
(while (string-match "\\([0-9]+\\)\\(?:-\\([0-9]+\\)\\)?" str start)
(push
(apply 'number-sequence
(seq-map 'string-to-int
(seq-filter
'identity
(list (match-string 1 str) (match-string 2 str)))))
ranges)
(setq start (match-end 0)))
(nreverse (seq-mapcat 'nreverse ranges))))
The code loops over the incoming string searching for plain numbers or ranges of numbers. On each match it calls number-sequence with either just a number for a plain match or two numbers for a range match and pushes each resulting number sequence into a list. To account for push building the result backwards, at the end it reverses all ranges in the list, concatenates them, then reverses the result and returns it.
Calling parse-integer-list with your example input:
(parse-integer-list "1-3, 4, 8, 18-21")
produces:
(1 2 3 4 8 18 19 20 21)
I am trying to write a function that takes a matrix (represented as a list of lists) and adds the elements down the columns and returns a vector (represented as a list):
Example:
(define sample
'((2 6 0 4)
(7 5 1 4)
(6 0 2 2)))
should return '(15 11 3 10).
I was trying to use the (list-ref) function twice to obtain the first element of each column with no luck. I am trying something like:
(map (lambda (matrix) ((list-ref (list-ref matrix 0) 0)) (+ matrix))
The solution is simple if we forget about the indexes and think about higher-order procedures, try this:
(define sample
'((2 6 0 4)
(7 5 1 4)
(6 0 2 2)))
(apply map + sample)
=> '(15 11 3 10)
Explanation: map can take multiple lists as arguments. If we apply it to sample (which is a list of lists) and pass + as the procedure to do the mapping, it'll take one element from each list in turn and add them, producing a list with the results - effectively, adding all the columns in the matrix.
Quick question trying to figure this out before an exam I have.
If I have a nested list such as
(list 1 (list 2 3 ( list 4 (list 6))))
How would I write a function that would give me the lowest level only or the 3rd level?
For example the lowest level would output '(6) and the 3rd would output '(4).
I was debating maybe using a flattem but then I wouldn't know the levels.
Any help would be greatly appreciated.
Use recursive descent and pass the current level as an extra argument.
(define (collect s-exp level) ...)
1. If s-exp is empty return '()
2. If s-exp is a pair, (cons a d), then
2a. if a is a pair, then recurse on a with an increased level
2b. if level is below 3
3a recurse on a
3b recurse on d
3c. append the results from 3a and 3b
2c if level is 3
4a recurse on d
4b append (list a) with the result from 4a
I'm doing some homework and for one part I have to generate random numbers in the range 10 - 80. I know (random 80) will return a number less than 80 but how do I get it to get the numbers to be above 10 as well?
Hint: (+ 1 (random 80)) will give you a number between 1 and 80 inclusive.
This code will give you random numbers from 10 to 80:
(+ 10 (random 71))
even better, try this general formula:
(defun random-from-range (start end)
(+ start (random (+ 1 (- end start)))))