emacs org-mode tree to list - elisp

I'm looking for a concise way to read a specific tree (including subtrees) into a list.
Say I've got:
* Branch
** Small branch
** Another small branch
*** Leaves
* Flowers
The function should be able to search by regular expression and copy the subtree (e.g. search for Branch) to a list like:
'(("Small branch") ("Another small branch" ("Leaves")))

The following seems to work:
(defun org-list-siblings ()
"List siblings in current buffer starting at point.
Note, you can always (goto-char (point-min)) to collect all siblings."
(interactive)
(let (ret)
(unless (org-at-heading-p)
(org-forward-heading-same-level nil t))
(while (progn
(setq ret (cons (append (list (substring-no-properties (org-get-heading)))
(save-excursion
(when (org-goto-first-child)
(org-list-siblings))))
ret))
(org-goto-sibling)))
(nreverse ret)))
If you do not need the full tree but a sub-tree put point on the first of its children headings.
That is methodical since the top-level headings are interpreted as the first children. There is no common root.

Related

Can I make this Clojure code (scoring a graph bisection) more efficient?

My code is spending most of its time scoring bisections: determining how many edges of a graph cross from one set of nodes to the other.
Assume bisect is a set of half of a graph's nodes (ints), and edges is a list of (directed) edges [ [n1 n2] ...] where n1,n2 are also nodes.
(defn tstBisectScore
"number of edges crossing bisect"
([bisect edges]
(tstBisectScore bisect 0 edges))
([bisect nx edge2check]
(if (empty? edge2check)
nx
(let [[n1 n2] (first edge2check)
inb1 (contains? bisect n1)
inb2 (contains? bisect n2)]
(if (or (and inb1 inb2)
(and (not inb1) (not inb2)))
(recur bisect nx (rest edge2check))
(recur bisect (inc nx) (rest edge2check))))
)))
The only clues I have via sampling the execution of this code (using VisualVM) shows most of the time spent in clojure.core$empty_QMARK_, and most of the rest in clojure.core$contains_QMARK_. (first and rest take only a small fraction of the time.) (See attached .
Any suggestions as to how I could tighten the code?
First I would say that you haven't expanded that profile deep enough. empty? is not an expensive function in general. The reason it is taking up all your time is almost surely because the input to your function is a lazy sequence, and empty? is the poor sap whose job it is to look at its elements first. So all the time in empty? is probably actually time you should be accounting to whatever generates the input sequence. You could confirm this by profiling (tstBisectScore bisect (doall edges)) and comparing to your existing profile of (tstBisectScore bisect edges).
Assuming that my hypothesis is true, almost 80% of your real workload is probably in generating the bisects, not in scoring them. So anything we do in this function can get us at most a 20% speedup, even if we replaced the whole thing with (map (constantly 0) edges).
Still, there are many local improvements to be made. Let's imagine we've determined that producing the input argument is as efficient as we can get it, and we need more speed.
When iterating eagerly over something, use next instead of rest. The point of rest is that it's a bit lazier, and always returns a non-nil sequence instead of peeking to see if there is a next element. If you know you will need the next element anyway, use next to get both bits of information at once.
In general, empty? is not an efficient way to test a sequence. (defn empty? [x] (not (seq x))) is obviously a wasted not. If you care about efficiency, write (seq x) instead, and invert your if branches. Better still, if you know x is the result of a next call, it can never be an empty sequence: only nil, or a non-empty sequence. So just write (if x ...).
(or (and inb1 inb2)
(and (not inb1) (not inb2)))
is a very expensive way to write (= inb1 inb2).
So for starters, you could instead write
(defn tstBisectScore
([bisect edges] (tstBisectScore bisect 0 (seq edges)))
([bisect nx edges]
(if edges
(recur bisect (let [[n1 n2] (first edges)
inb1 (contains? bisect n1)
inb2 (contains? bisect n2)]
(if (= inb1 inb2) nx (inc nx)))
(next edges))
nx)))
Note that I've also rearranged things a bit, by putting the if and let inside of the recur instead of duplicating the other arguments to the recur. This isn't a very popular style, and it doesn't matter to efficiency. Here it serves a pedagogical purpose: to draw your attention to the basic structure of this function that you missed. Your whole function has the structure(if xs (recur (f acc x) (next xs))). This is exactly what reduce already does!
I could write out the translation to use reduce, but first I'll also point out that you also have a map step hidden in there, mapping some elements to 1 and some to 0, and then your reduce phase is just summing the list. So, instead of using lazy sequences to do that, we'll use a transducer, and avoid allocating the intermediate sequences:
(defn tstBisectScore [bisect edges]
(transduce (map (fn [[n1 n2]]
(if (= (contains? bisect n1)
(contains? bisect n2)
0, 1)))
+ 0 edges))
This is a lot less code because you let existing abstractions do the work for you, and it should be more efficient because (a) these abstractions don't make the local mistakes you did, and (b) they also handle chunked sequences more efficiently, which is a sizeable boost that comes up surprisingly often when using basic tools like map, range, and filter.
This answer is based this answer from amalloy and shows some additional ways to speed up this code:
Use Java arrays:
Convert edges with (into-array (map into-array edges)). This allows you to use operations like aget, aset and especially areduce.
Use Java functions
In the following code, I replaced = with .equals and contains? with .contains.
Use type hints
Using these tips, I rewrote your function like this:
(defn tst-bisect-score [^HashSet bisect
^"[[Ljava.lang.Long;" edges]
(areduce edges
i
ret
(long 0)
(+ ret
(let [^"[Ljava.lang.Long;" e (aget edges i)]
(if (.equals ^Boolean
(.contains ^HashSet bisect
^Long (aget e 0))
^Boolean
(.contains ^HashSet bisect
^Long (aget e 1)))
0 1)))))
Convert your arguments in advance with (HashSet. ^Collection bisect) and (into-array (map into-array edges)) and then call:
(tst-bisect-score bisect edges)

Having trouble with a function in Scheme

so i am trying to understand this piece of code, and after staring at it for far too long i decided to ask here if anyone could help me understand how and why it works
(define knock-knock
(letrec ([dig (lambda (i)
(cons (* i (list-ref knock-knock (- i 1)))
(dig (+ i 1))))])
(cons 1 (dig 1))))
the function is then called by name with the value:
(list-ref knock-knock 5)
So my main problem is that i can not see where the letrec would end. the other thing is that i am not given a list, so what is the 4th element in the list that i am supposed to reference in line 3?
First, a note: this is not normal Scheme, as it requires lazy evaluation.
In lazy evaluation, values are only computed when they are needed. So, for defining knock-knock, we can just do
(cons 1 <thunk: (dig 1)>)
i.e., we generate a pair, but we don't need the second element, so we defer its evaluation until later.
When we actually want to evaluate the second element, we will already have knock-knock defined, so we can reference it.
The next element is computed by taking the previous (i-1-st) element, and multiplies it by i. So this will generate the series {n!}: 1,1,2,6,24,...
A straightforward translation of this code to the (normally lazy) Haskell language goes like this:
knock :: [Int]
knock = 1 : dig 1
where dig i = (i * knock !! (i-1)) : dig (i+1)

Scheme Path In Binary Tree

I got an exercice to find the path of a binary tree in Scheme.
Basically, it's like Find all paths from root to leaves of tree in Scheme.
But instead of printing the value of nodes, we have to print the way to get to the leaf. ( print : right left left right for ex)
If you are talking about finding the path from root to a specific leaf you can basically search your tree recursively and while doing that you should pass a list to your search function as parameter to keep track of the path already taken and your search function should return path list.
For example, let's say you are searching for L in your tree, you need to check whether L is in left or right subtree. After finding the subtree in which L is located you can basically add the direction to your path list, you can do something like
(define (search L tree)
(cond
((null? tree) '() )
((member L leftsubtree ) (cons 'left (search L leftsubtree))
((member L rightsubtree) (cons 'right (search L rightsubtree)))))
What we do here is we found the subtree L is located and then add the direction (left or right) to the front of the path from parent of that subtree to L. Of course if you copy and paste this code it does not work. So you need to implement this function in accordance with your tree representation, and you probably need to implement member function for your case. I hope it helps.
(define (ab-chemin-aux AB e CH)
(if (ab-noeud? AB)
(if (equal? e (ab-etiquette AB))
CH
(or (ab-chemin-aux (ab-gauche AB) e (append CH (list "gauche")))
(ab-chemin-aux (ab-droit AB) e (append CH (list "droit")))))#f))
(define (ab-chemin AB e)
(ab-chemin-aux AB e (list)))
I figured out the answer but I forgot about asking here. Thank you for your answer. Hope this help someone

relation between foldr and append in Scheme

try to figure out how to use "append" in Scheme
the concept of append that I can find like this:
----- part 1: understanding the concept of append in Scheme-----
1) append takes two or more lists and constructs a new list with all of their elements.
2) append requires that its arguments are lists, and makes a list whose elements are the elements of those lists. it concatenates the lists it is given. (It effectively conses the elements of the other lists onto the last list to create the result list.)
3) It only concatenates the top-level structure ==> [Q1] what does it mean "only concatenates the top-level"?
4) however--it doesn't "flatten" nested structures.
==> [Q2] what is "flatten" ? (I saw many places this "flatten" but I didn't figure out yet)
==> [Q3] why append does not "flatten" nested structures.
---------- Part 2: how to using append in Scheme --------------------------------
then I looked around to try to use "append" and I saw other discussion
based on the other discussion, I try this implementation
[code 1]
(define (tst-foldr-append lst)
(foldr
(lambda (element acc) (append acc (list element)))
lst
'())
)
it works, but I am struggling to understand that this part ...(append acc (list element)...
what exactly "append" is doing in code 1, to me, it just flipping.
then why it can't be used other logics e.g.
i) simply just flip or
iii).... cons (acc element).....
[Q4] why it have to be "append" in code 1??? Is that because of something to do with foldr ??
again, sorry for the long question, but I think it is all related.
Q1/2/3: What is this "flattening" thing?
Scheme/Lisp/Racket make it very very easy to use lists. Lists are easy to construct and easy to operate on. As a result, they are often nested. So, for instance
`(a b 34)
denotes a list of three elements: two symbols and a number. However,
`(a (b c) 34)
denotes a list of three elements: a symbol, a list, and a number.
The word "flatten" is used to refer to the operation that turns
`(3 ((b) c) (d (e f)))
into
`(3 b c d e f)
That is, the lists-within-lists are "flattened".
The 'append' function does not flatten lists; it just combines them. So, for instance,
(append `(3 (b c) d) `(a (9)))
would produce
`(3 (b c) d a (9))
Another way of saying it is this: if you apply 'append' to a list of length 3 and a list of length 2, the result will be of length 5.
Q4/5: Foldl really has nothing to do with append. I think I would ask a separate question about foldl if I were you.
Final advice: go check out htdp.org .
Q1: It means that sublists are not recursively appended, only the top-most elements are concatenated, for example:
(append '((1) (2)) '((3) (4)))
=> '((1) (2) (3) (4))
Q2: Related to the previous question, flattening a list gets rid of the sublists:
(flatten '((1) (2) (3) (4)))
=> '(1 2 3 4)
Q3: By design, because append only concatenates two lists, for flattening nested structures use flatten.
Q4: Please read the documentation before asking this kind of questions. append is simply a different procedure, not necessarily related to foldr, but they can be used together; it concatenates a list with an element (if the "element" is a list the result will be a proper list). cons just sticks together two things, no matter their type whereas append always returns a list (proper or improper) as output. For example, for appending one element at the end you can do this:
(append '(1 2) '(3))
=> '(1 2 3)
But these expressions will give different results (tested in Racket):
(append '(1 2) 3)
=> '(1 2 . 3)
(cons '(1 2) '(3))
=> '((1 2) 3)
(cons '(1 2) 3)
=> '((1 2) . 3)
Q5: No, cons will work fine here. You wouldn't be asking any of this if you simply tested each procedure to see how they work. Please understand what you're using by reading the documentation and writing little examples, it's the only way you'll ever learn how to program.

SICP Accumulate function

In Structure and Interpretation of Computer Programs (SICP) Section 2.2.3 several functions are defined using:
(accumulate cons nil
(filter pred
(map op sequence)))
Two examples that make use of this operate on a list of the fibonacci numbers, even-fibs and list-fib-squares.
The accumulate, filter and map functions are defined in section 2.2 as well. The part that's confusing me is why the authors included the accumulate here. accumulate takes 3 parameters:
A binary function to be applied
An initial value, used as the rightmost parameter to the function
A list to which the function will be applied
An example of applying accumulate to a list using the definition in the book:
(accumulate cons nil (list 1 2 3))
=> (cons 1 (cons 2 (cons 3 nil)))
=> (1 2 3)
Since the third parameter is a list, (accumulate cons nil some-list) will just return some-list, and in this case the result of (filter pred (map op sequence)) is a list.
Is there a reason for this use of accumulate other than consistency with other similarly structured functions in the section?
I'm certain that those two uses of accumulate are merely illustrative of the fact that "consing elements to construct a list" can be treated as an accumulative process in the same way that "multiplying numbers to obtain a product" or "summing numbers to obtain a total" can. You're correct that the accumulation is effectively a no-op.
(Aside: Note that this could obviously be a more useful operation if the output of filter and input of accumulate was not a list; for example, if it represented a lazily generated sequence.)

Resources