Ross Dunkley Posted July 24, 2019 Posted July 24, 2019 Hi, I have a list in the following format... I guess its like a list within a list (sublist) (It's from Lee Mac's Update Titleblock routine if you're interested..!) (("" "" "") ("" "Test" "") ("" "" "") ("" "" "")) What I am trying to do is to return an element (sublist) that matches a particular criteria. I have been trying to do this with the following code I found online... ;; CAB 12/17/2009 ;; returns a list matching items from the list (defun getMatching (pat lst / i mlst) (mapcar (function (lambda (x) (and (wcmatch x pat) (setq mlst (cons x mlst))))) lst) (reverse mlst)) If I try to test this I get the following... "Error: bad argument type: stringp ("" "" "") (setq list1 '(("" "" "") ("" "Test" "") ("" "" "") ("" "" ""))) (defun c:test() (print (getMatching "*Test*" list1)) (princ) ) Regards. Quote
Tharwat Posted July 24, 2019 Posted July 24, 2019 (defun getMatching (pat lst / i mlst) (mapcar (function (lambda (x) (mapcar '(lambda (s) (and (wcmatch s pat) (setq mlst (cons s mlst)))) x ) ) ) lst ) (reverse mlst) ) Quote
Ross Dunkley Posted July 24, 2019 Author Posted July 24, 2019 Thanks Tharwat, This returns the element ("Test") What I am trying to get is the entire sub-list (or list within the list) that matches the criteria. For example... ("" "Test" "") This is because the actual list will have several elements that I need to work with. Would using vl-remove-if-not be the way to go? If so, how might this look? Quote
Tharwat Posted July 24, 2019 Posted July 24, 2019 This? (defun getMatching (pat lst / i mlst) (mapcar (function (lambda (x) (vl-some '(lambda (s) (and (wcmatch s pat) (setq mlst (cons x mlst)))) x ) ) ) lst ) (reverse mlst) ) 1 Quote
Tharwat Posted July 24, 2019 Posted July 24, 2019 You're welcome anytime. NOTE: You can remove the localized variable ( i ) from the function since its useless. Quote
Grrr Posted July 24, 2019 Posted July 24, 2019 FWIW - ;| _$ (wcmatchList "test##" nil '(("test12")( "Test123" "re23" "asd") "32test" ("fd" "tEst55" "dsda"))) >> ("test12") _$ (wcmatchList "test##" t '(("test12")( "Test123" "re23" "asd") "32test" ("fd" "tEst55" "dsda"))) >> ("test12" "tEst55") |; (defun wcmatchList ( pat case L / x c ) (cond ( (not L) L) ( (listp (setq x (car L))) (append (wcmatchList pat case x) (wcmatchList pat case (cdr L))) ) ( (append (if (progn (setq c x) (if case (mapcar 'set '(x pat) (mapcar 'strcase (list x pat)))) (wcmatch x pat) ) (list c) ) (wcmatchList pat case (cdr L)) ) ) ); cond ); defun wcmatchList Quote
Lee Mac Posted July 24, 2019 Posted July 24, 2019 If you wish to return the first match found: (defun getmatch ( p l ) (vl-some '(lambda ( x ) (if (vl-some '(lambda ( y ) (wcmatch y p)) x) x)) l) ) _$ (getmatch "*Test*" '(("" "" "") ("" "TestA" "") ("" "" "TestB") ("TestC" "" ""))) ("" "TestA" "") If you wish to return all matches found: (defun getmatches ( p l ) (vl-remove-if-not '(lambda ( x ) (vl-some '(lambda ( y ) (wcmatch y p)) x)) l) ) _$ (getmatches "*Test*" '(("" "" "") ("" "TestA" "") ("" "" "TestB") ("TestC" "" ""))) (("" "TestA" "") ("" "" "TestB") ("TestC" "" "")) Aside @Tharwat: a relatively minor point, but if the list value returned by mapcar is not being used, in my opinion a foreach loop may be more applicable. 1 Quote
Steve in Alaska Posted January 15, 2020 Posted January 15, 2020 Here is my adjustment of Lee Mac's "GetMatch" to allow searching for either text or numbers by using "Member". This works for me as the search term is always the first term in the list. Also strips our the search term from the result. Lee, can you offer any advice on how to return the whole list if the search term is not the first term in the list? (defun getmatch (SearchTerm ListToSearch) (vl-some '(lambda (x) (member SearchTerm x ) ) ;_ end of lambda ListToSearch ) ;_ end of vl-some ) ;_ end of defun Quote
Steve in Alaska Posted January 15, 2020 Posted January 15, 2020 I think I figured it out, wrap " (member SearchTerm x )" in an If statement with the result being "x" if true. Quote
Lee Mac Posted January 15, 2020 Posted January 15, 2020 (edited) Hi Steve, Assuming I've understood your intention, you could use either of the following (vl-position is typically faster than member) (defun getmatch ( x l ) (vl-some '(lambda ( y ) (if (member x y) y)) l) ) (defun getmatch ( x l ) (vl-some '(lambda ( y ) (if (vl-position x y) y)) l) ) Note that your original code would have returned the list item including the search term. Edited January 15, 2020 by Lee Mac Quote
Steve in Alaska Posted January 16, 2020 Posted January 16, 2020 Thank you Sir, Your code always works well, and I have learned a lot from it. Just so you know the purpose behind this effort, I have a list of tables with corresponding column widths. Each table is identified by either a string, an integer or a real ("840.STEEL", 841, 803.1). This lisp pulls the information for the table from a master list of lists that have the table id and column widths. I have another lisp that sets each table's column widths with the returned results. All in an effort to ensure conformity. Each of the tables gets fed by a linked excel sheet, which the Engineers and Architects are more comfortable editing. The link from excel initially sets the column width based on what is in the excel sheet, but the excel sheet has some difficulties being accurate due to how it bases cell width based on font character sizing. I also use your routine to strip out embedded format codes, so that the table style can control what is in the cells. Yep, I was using a "Cdr" on the returned result, so I didn't see the search term in the result. Like so (SetQ result (cdr(getmatch "840.STEEL" MyList))) or (SetQ result (cdr(getmatch 803.1 MyList))) SteveInAlaska Quote
BIGAL Posted January 16, 2020 Posted January 16, 2020 I tried doing something similar for column widths and used STRLEN and a fuzzy factor, in my case looked at a list and got max strlen. It was not very reliable though. Quote
Lee Mac Posted January 16, 2020 Posted January 16, 2020 You're most welcome @Steve in Alaska, I'm delighted to hear that you could learn from my contributions. FWIW, since you are essentially using a key to obtain associated information, assoc may be more applicable, e.g.: (cdr (assoc "840.STEEL" MyList)) Though this of course requires that the key be the first element in the sublist. Quote
Steve in Alaska Posted January 16, 2020 Posted January 16, 2020 @Lee Mac, Yes, but I tend to make my lisp coding usable for more than one application, hence my interest in a solution that works for just about any way you would want to return a specific list from a "Master" list. For what its worth, here is a small section of my code that creates the "Master lists of Table Columns", in reality there are a little over (50) different tables, some are identical. (SetQ MyList (list '(800 0.625 1 1 1 2.1875 2.1875) '("800.AK" 0.625 1 1 1 3.1875 1.1875) '(801 0.625 1 1 1 4.375) '(802 0.625 1 1 1 1 1 2.375) '(803 0.625 1.25 1.25 1.25 1.25 2.375) ) ;_ end of list ) ;_ end of SetQ And after separating out the column widths list for a specific table, I have this code (not yet finished, I need to chase down the parenthesis still and comment it better). (Defun SetTblColWidth (TblType ListTblColWidth / CounterCol#) ;;; USAGE - (SetTblColWidth 800 '(0.6250 1.0000 1.0000 1.0000 2.1875 2.1875 )) (cond ( ;cond1 (= (length ListTblColWidth) Number_COLS) (setQ CounterCol# 0) (repeat (length ListTblColWidth) (vla-setcolumnwidth TblObj CounterCol# (nth CounterCol# ListTblColWidth)) (setQ CounterCol# (1+ CounterCol#) ) ;_ end of setQ ) ;end cond1 ( ;cond2 (/= Number_COLS Number_COLS) (alert (strcat "Columns mismatch, The Table Type " (rtos TblTypE 2 0) " actually has " " and the Table.LSP expects " (ITOA (length ListTblColWidth)) ) ;_ end of strcat ) ;_ end of alert ) ;end cond2 ) ) ;_ end of cond ) ;_ end of Defun Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.