(defun f ( func lst / LM:Flatten lstf lstfn lsts lstfs lstfns lstfsa lstsn pos )
(defun LM:Flatten ( l )
(if (atom l) (list l)
(append (LM:Flatten (car l)) (if (cdr l) (LM:Flatten (cdr l))))
)
)
(setq lstf (LM:Flatten lst))
(setq lstfn (mapcar 'func lstf))
(setq lsts (vl-prin1-to-string lst))
(setq lstfs (mapcar '(lambda ( x ) (vl-prin1-to-string x)) lstf))
(setq lstfns (mapcar '(lambda ( x ) (vl-prin1-to-string x)) lstfn))
(setq lstfsa (mapcar '(lambda ( a b ) (list a b)) lstfs lstfns))
(setq lstsn lsts)
(setq pos 0)
(foreach el lstfsa
(setq lstsn (vl-string-subst (cadr el) (car el) lstsn pos))
(setq pos (1+ (vl-string-search (cadr el) lstsn pos)))
)
(read lstsn)
)
_$ (map-nested '1+ '((((1 3)) (2 4) (((5 7))) (6) ((8)) 8 7 6 5 4 3 2 1)))
((((2 4)) (3 5) (((6 8))) (7) ((9)) 9 8 7 6 5 4 3 2))
If elements are some other type of data, then the function you send to mapcar / this map-nested should check for such eventuality. Say you've got a situation where you want all integers incremented by 5, all strings changed to uppercase, and all reals left as is:_$ (map-nested '(lambda (item) (cond ((= (type item) 'Str) (strcase item))
((= (type item) 'Int) (+ item 5))
(t item)))
'((((1 "test")) (2 4) (((5.0 7))) (6) ((8)) 8 7 6 5 4 3 2 1)))
((((6 "TEST")) (7 9) (((5.0 12))) (11) ((13)) 13 12 11 10 9 8 7 6))
Or, to account for dotted pairs:That's a good point, just one question: Why do you skip nil values? I was thinking of this, but figured, since mapcar doesn't do so, why should others?
_$ (quickbench '((map-nested1 f l) (map-nested2 f l) (fnest f l) (fnest2 f l)))
Benchmarking .... done for 8192 iterations. Sorted from fastest.
Statement Increment Time(ms) Normalize Relative
--------------------------------------------------------------------------------
(FNEST2 F L) 8192 1264 1264 1.30
(FNEST F L) 8192 1435 1435 1.14
(MAP-NESTED2 F L) 8192 1544 1544 1.06
(MAP-NESTED1 F L) 8192 1638 1638 1.00
--------------------------------------------------------------------------------
Seems my idea of forcing mapcar improves on my defun, but the overhead of making and calling extra functions is less efficient (should have figured this on my own :embarrassed:).What is surprising is the fnest2. It's not as if it does much different from your fnest ???Ah! Just realized: kind of logical if you think about it.
_$ (fnest '1+ nil)
nil
_$ (map-nested1 '1+ nil)
nil
_$ (mapcar 'not '(t nil t nil))
(nil T nil T)
_$ (fnest 'not '(t nil t nil))
(nil nil nil nil)
_$ (fnest2 'not '(t nil t nil))
(nil T nil T)
_$ (mapcar '1+ '(1 2 nil 4))
; error: bad argument type: numberp: nil
_$ (fnest '1+ '(1 2 nil 4))
(2 3 nil 5)
_$ (fnest2 '1+ '(1 2 nil 4))
; error: bad argument type: numberp: nil
_$ (map-nested1 '1+ '(1 2 nil 4))
; error: bad argument type: numberp: nil
_$ (map-nested1 'not '(t nil t nil))
(nil T nil T)
_$ (map-nested1 'not nil)
nil
So, which are the most consistent as compared to mapcar?
So, which are the most consistent as compared to mapcar?That is a very good point. The problem is of course that nil is inconsistent since it is both an atom and a list.
On a fundamental level it is strange that your map-nested functions treat the 'top-level' nil as a list and any nested nil as an atom.That's due to them working much more in line with the same way as mapcar does. In fact that is exactly what mapcar does. But the last 2 variants have moved away from mapcar's method in order to accommodate the dotted pairs, which mapcar disallows.
And a list with 15000 items or levels seems unlikely as input for a map-nested function.True chances of that happening is extremely slim in theory, but I've run into them and I've seen some of them on these forums. So they're not something which "never" happens. I'm just stating you should keep note that they could happen.
Note:Yes, that is a bit confusing. In that sense my original map-nested is probably much closer to mapcar:
(map-nested2 '1+ '(1 2 . 3 )) => (2 3)
(fnest '1+ '(1 2 . 3 )) => (2 3 . 4)
Command: (mapcar '1+ '(1 2 . 3))
; error: bad list: 3
(defun Iter_fNest (Expr Lst / Stack Result Dim)
(while (or Lst Stack)
(cond
((null Lst)
(setq Lst (car Stack))
(setq Stack (cdr Stack))
(setq Result
(cons
( (lambda ( / O)
(repeat (car Dim)
(setq O (cons (car Result) O))
(setq Result (cdr Result))
)
(setq Dim (cdr Dim))
O
)
)
Result
)
)
)
((atom (car Lst))
(setq Result (cons ((eval Expr) (car Lst)) Result))
(setq Lst (cdr Lst))
)
((listp (car Lst))
(setq Stack (cons (cdr Lst) Stack))
(setq Lst (car Lst))
(setq Dim (cons (length Lst) Dim))
)
)
)
(reverse Result)
)
(Iter_Fnest '(lambda (a / ) (print a) (1+ a)) '((1 2) 3 4 5 (6 (7 (8) 9) 10 (11 (12 (13 14) 15) 16) 17) 18 (19 20)))
( (lambda (fnest2 / )
(eval (list 'defun 'anon_fnest2 '(f l / ) (list fnest2 fnest2 'f 'l)))
)
(lambda (fnest2 f l / )
(cond ((atom l) ((eval f) l))
((cdr l) (cons (fnest2 fnest2 f (car l)) (fnest2 fnest2 f (cdr l))))
((cons (fnest2 fnest2 f (car l)) nil))
)
)
)
Irneb,If you want you can use it yourself. It's one I derived from this one: http://www.theswamp.org/lilly_pond/mp/lisp/benchmark.txt (http://www.theswamp.org/lilly_pond/mp/lisp/benchmark.txt)
can u test this with ur bench-thing?
Im wondering if it makes any difference:
I picked up fnest2 and have made the recursion 'anonym'... the recursion is calling a compiled lambda-expr...Code: [Select]( (lambda (fnest2 / )
(eval (list 'defun 'anon_fnest2 '(f l / ) (list fnest2 fnest2 'f 'l)))
)
(lambda (fnest2 f l / )
(cond ((atom l) ((eval f) l))
((cdr l) (cons (fnest2 fnest2 f (car l)) (fnest2 fnest2 f (cdr l))))
((cons (fnest2 fnest2 f (car l)) nil))
)
)
)
(anon_fnest2 '1+ '((1 2) (3 . 4) (5 6 (7 8 ((((9)) 10 11))))))
Greets Reltro
_$ (quickbench '((fNest 'test lst) (fNest2 'test lst) (Iter_fNest 'test lst) (map-nested 'test lst) (map-nested1 'test lst) (map-nested2 'test lst)))
Benchmarking ...... done for 8192 iterations. Sorted from fastest.
Statement Increment Time(ms) Normalize Relative
--------------------------------------------------------------------------------
(FNEST2 (QUOTE TEST) LST) 8192 1265 1265 1.70
(FNEST (QUOTE TEST) LST) 8192 1341 1341 1.60
(MAP-NESTED2 (QUOTE TEST) LST) 8192 1482 1482 1.45
(MAP-NESTED1 (QUOTE TEST) LST) 8192 1623 1623 1.33
(MAP-NESTED (QUOTE TEST) LST) 8192 1716 1716 1.25
(ITER_FNEST (QUOTE TEST) LST) 4096 1076 2152 1.00
--------------------------------------------------------------------------------
It does work on nils inside the list, but not dotted pairs. So it's comparable to my first map-nested function as well as the built-in mapcar. But it's not comparable to Lee's fnest and those which were derived from it. I suppose it depends on what you want to achieve from this code:_$ (quickbench '((fNest 'test lst) (fNest2 'test lst) (anon_fNest2 'test lst)))
Benchmarking ... done for 8192 iterations. Sorted from fastest.
Statement Increment Time(ms) Normalize Relative
--------------------------------------------------------------------------------
(FNEST2 (QUOTE TEST) LST) 8192 1294 1294 1.05
(ANON_FNEST2 (QUOTE TEST) LST) 8192 1327 1327 1.02
(FNEST (QUOTE TEST) LST) 8192 1358 1358 1.00
--------------------------------------------------------------------------------
AFAICT it's needlessly complicating the code. What was your reasoning in generating a labda function which generates your defun function to use your generated lambda function which then calls itself using a parameter passed into itself so it has a reference to itself? See how convoluted it even sounds?_$ (quickbench '((fnest 'test lst) (anon_fNest2a 'test lst) (fNest2 'test lst) (anon_fNest2 'test lst)))
Benchmarking .... done for 8192 iterations. Sorted from fastest.
Statement Increment Time(ms) Normalize Relative
--------------------------------------------------------------------------------
(FNEST2 (QUOTE TEST) LST) 8192 1294 1294 1.05
(ANON_FNEST2A (QUOTE TEST) LST) 8192 1311 1311 1.04
(FNEST (QUOTE TEST) LST) 8192 1327 1327 1.02
(ANON_FNEST2 (QUOTE TEST) LST) 8192 1358 1358 1.00
--------------------------------------------------------------------------------
It might have improved something on the reciprocal recursion of the map-nested2 if the definition was the slowing factor. But I've even tested that version using premade defuns for the runMap & doItem nested functions. It makes no difference at all_$ (quickbench '((map-nested2 'test lst) (map-nested3 'test lst)))
Benchmarking .. done for 8192 iterations. Sorted from fastest.
Statement Increment Time(ms) Normalize Relative
--------------------------------------------------------------------------------
(MAP-NESTED2 (QUOTE TEST) LST) 8192 1434 1434 1.11
(MAP-NESTED3 (QUOTE TEST) LST) 8192 1590 1590 1.00
--------------------------------------------------------------------------------
So you see the major time taken seems to be the overhead of calling the function, not the time taken to generate the function.
(defun Iter_fNest (Expr Lst / Stack Result Dim)
(while (or Lst Stack)
(cond
((null Lst)
(setq Lst (car Stack))
(setq Stack (cdr Stack))
(setq Result
(cons
( (lambda ( / O)
(repeat (caar Dim)
(setq O (cons (car Result) O))
(setq Result (cdr Result))
)
(if (cdar Dim)
(apply 'vl-list* O)
O
)
)
)
Result
)
)
(setq Dim (cdr Dim))
)
((atom (car Lst))
(setq Result (cons ((eval Expr) (car Lst)) Result))
(setq Lst (cdr Lst))
)
('T
(setq Stack (cons (cdr Lst) Stack))
(apply
'(lambda (L D / )
(setq Lst L)
(setq Dim (cons (cons (length Lst) D) Dim))
)
( (lambda (a / lst s)
(setq s a)
(while (not (atom (cdr a)))
(setq lst (cons (car a) lst))
(setq a (cdr a))
)
(cond
((cdr a)
(list
(setq lst (reverse (vl-list* (cdr a) (car a) lst)))
'dP
)
)
('T (list s nil))
)
)
(car Lst)
)
)
)
)
)
(reverse Result)
)
(iter_fnest '1+ '(((1 (3 . 4) 5) . 3) (1 . 20) 2 3 (1 2 (3 4) . 5) 4))
AFAICT it's needlessly complicating the code. What was your reasoning in generating a labda function which generates your defun function to use your generated lambda function which then calls itself using a parameter passed into itself so it has a reference to itself? See how convoluted it even sounds?
(setq anonRec
( (lambda (rec / )
(eval
(list 'lambda '(expr / in)
(list rec rec
'expr
'((lambda (a b / ) (if a (reverse (cdr a)) b))
(member '/ (reverse (cdr (cadr expr))))
(cdr (cadr expr))
)
)
)
)
)
(eval
(function
(lambda (rec expr in / )
(eval
(eval
(list 'function
(list 'lambda in
(vl-list*
expr
(list rec rec (list 'quote expr) (list 'quote in))
in
)
)
)
)
)
)
)
)
)
)
( (anonRec
'(lambda (ME a / c)
(print a)
(if (> a 0)
(ME (1- a))
)
)
)
200
)
$ (setq test '(1 2 3 4 5 6 7 8 9))
(1 2 3 4 5 6 7 8 9)
_$ (quickbench '((foreach-recursive 'x test '(1+ x)) (foreach-iterative 'x test '(1+ x)) (foreach x test (1+ x))))
Benchmarking ... done for 16384 iterations. Sorted from fastest.
Statement Increment Time(ms) Normalize Relative
--------------------------------------------------------------------------------
(FOREACH X TEST (1+ X)) 16384 1187 1187 5.20
(FOREACH-ITERATIVE (QUOTE X) TEST (Q...) 4096 1264 5056 1.22
(FOREACH-RECURSIVE (QUOTE X) TEST (Q...) 4096 1543 6172 1.00
--------------------------------------------------------------------------------
Of course using the built-in foreach is a lot quicker as it's fully compiled (probably written in C as well).