1

I need to find the leaves in a list in Scheme.

For example, if I have (1 (2 3) (4 (5) (7 (8) (10 11 12)))))), my leaves are (8) and (10 11 12). So my function will return (1 (2 3) (4 (5) (7 leaf1 leaf2))))).

Definition: a leaf is an element with the deepest nesting possible.

Examples: In (1 (2 (3))) the element (3) is a leaf.

In ((1 2) (3 4)) the elements (1 2) and (3 4) are leaves.

I tried to use the map function, that will check if the list is composed from lists. If it is - so I call the function again, and if not, I break and change the lists to symbols of leafs. It doesn't work.

I have been stuck on it for 2 days. I am trying to find an idea, not an implementation. Thanks.

crashmstr
  • 28,043
  • 9
  • 61
  • 79
Adam Sh
  • 8,137
  • 22
  • 60
  • 75
  • How are you defining a "leaf"? If it's just a list which doesn't contain other lists, why are `(8)` and `(10 11 12)` considered leafs in your example while `(2 3)` and `(5)` are not? That seems like half the problem to me... –  Dec 02 '11 at 13:31
  • Thanks for clarifying. It still seems ambiguous, though: should the leaf in `(1 (2 (3)))` be `(3)` rather than `3`? If you're going to descend down to the level of list elements, then the leaves in your first example should be `8`, `10`, `11`, and `12`. –  Dec 02 '11 at 14:36
  • @JonO: Yes. It should be '(3)'. Sorry – Adam Sh Dec 02 '11 at 14:54
  • The term "leaf" has a specific meaning, and you're not using it; you should re-title your question as, perhaps, "find most deeply nested lists"... if that's what you're trying to do. I'm hoping this is homework? – John Clements Dec 02 '11 at 17:11
  • @JohnClements This is a little part of program that I need to write (the program is homework, and for that I ask only for an idea. – Adam Sh Dec 02 '11 at 17:19

1 Answers1

2

This is a little tricky to get right. Here are a few suggestions on one way to do it:

As stated, the problem is to walk the list, finding the most deeply nested lists that don't contain any other lists (these are sometimes called "lists of atoms"), and replacing them with something else. It's possible to do this in one recursive function, but I think it's clearer to break it up into parts:

  1. First, we need a predicate (a function that returns a boolean #t or #f) to determine whether a list is a list of atoms. (This is sometimes called lat?). You can write this as a simple recursive function, or you could use the library functions any and list?

  2. Then we need a function (define (max-lat-depth lst) ...) to find how deeply nested the most-deeply-nested list of atoms in its argument is. This will be a doubly recursive function -- it needs to check the first of each list as well as all the elements in the rest. We can define max-lat-depth as follows:

    a. If the argument is a lat itself, the maximum depth is zero, so (max-lat-depth '(1 2 3)) == 0

    b. If the first element of the argument isn't a list, it can't affect the maximum nesting depth overall. So in this case the max-lat-depth of the whole argument will be the same as the max-lat-depth of the rest (cdr) of the list: (max-lat-depth '(1 (2 (3 4))) == (max-lat-depth '((2 (3 4))) == 2

    c. The tricky case: if the first element of the argument is a list (as in ((1 2) (3 4))), we'll need to recur on both the first (or car) and rest (or cdr) of lst, returning the maximum of these values. However, we need to add 1 to one of these two results before taking the maximum. I'll let you figure out which one and why.

  3. Finally, we write a function (define (replace-lats-at-depth depth lst r) ...) that will take a nesting depth as returned from max-lat-depth, a list lst, and a replacement r. It will return a copy of lst where all the lists-of-atoms at depth depth have been replaced by r. For example:

(replace-lats-at-depth 0 '(1 2 3) '*) == '*

(replace-lats-at-depth 1 '(1 (2) 3) '*) == '(1 * 3).

Like max-lat-depth, replace-lats-at-depth recurs on both the first and rest of lst. It will call cons on the result of its recursive calls to construct a new tree structure. Also like max-lat-depth, it has several cases, and it will need to subtract 1 from depth in one of its recursive calls.

Once you have replace-lats-at-depth working to replace the nested lists with a constant value r, it shouldn't be too hard to improve it with a function that produces leaf1, leaf2, etc. as in your original example.

I hope that's helpful without saying too much. Let me know if not and I can try to clarify.

  • Dear jon O, If I want to know which leafs I changes, this is a big change? meaning: If in my example I change (8) and (10 11 12) to leaf1 and leaf2, so I return ((8) leaf1) and ((10 11 12) leaf2). Thanks – Adam Sh Dec 03 '11 at 19:14
  • @AdamSh: On second reading, I'm not quite sure what you're asking here. It might be worth making a separate question so you can explain in more detail. –  Dec 04 '11 at 09:51
  • I open a new question. Thank you. http://stackoverflow.com/questions/8389649/scheme-find-most-deeply-values-nested-lists – Adam Sh Dec 05 '11 at 17:56