Author Topic: [challenge] A29 : String Index  (Read 594 times)

0 Members and 1 Guest are viewing this topic.

JohnK

  • Administrator
  • Seagull
  • Posts: 10140
[challenge] A29 : String Index
« on: February 28, 2022, 08:59:27 AM »
Create a function that returns the indices of the vowels in a string (A E I O U Y).

NOTE:
        - You should design your indexer to be easily changed to support other conditions (`isvowel`, `ischar`, `isspace`, etc).

Examples
(string-index 'isvowel "apple")
> (1 5)

(string-index 'isvowel "hello")
> (2 5)

(string-index 'isvowel "STRAWBERRY")
> (4 7 10)

(string-index 'isvowel "pInEaPPLe")
> (2 4 5 9)

(string-index 'isvowel "ABCDCDEFGHIJ6789+%*/&|KLMNOPQRS 4567 %*/&|^~ qABCDrstuvwx'#()[]{ !<>;,.:? ABCD0123EFGH6789+%*/&|IJKLMNOfghijklABCDmnop8739qrstuvwxyz'#()ABCD[]{}=-0123456789+%*/&|^~!<>;,.:?")
> (1 7 11 27 47 54 75 83 97 103 107 111 117 127 131 137)
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

pBe

  • Bull Frog
  • Posts: 401
Re: [challenge] A29 : String Index
« Reply #1 on: February 28, 2022, 11:24:23 AM »
Code - Auto/Visual Lisp: [Select]
  1. (defun isvowel (e)
  2.   (wcmatch e "[Aa],[Ee],[Ii],[Oo],[Uu],[Yy]")
  3.   )
  4.  

Code - Auto/Visual Lisp: [Select]
  1. (defun string-index (f s)
  2.   ( (lambda (sl i )
  3.      (while (> (setq sl (1- sl)) 0)
  4.        (if ((eval f) (substr s sl 1))
  5.          (setq i (cons sl i))))
  6.      i )
  7.     (1+ (strlen s))
  8.     nil
  9.   )
  10. )

JohnK

  • Administrator
  • Seagull
  • Posts: 10140
Re: [challenge] A29 : String Index
« Reply #2 on: February 28, 2022, 11:34:25 AM »
Nice, I didn't think about using wcmatch.

Code - Auto/Visual Lisp: [Select]
  1. (defun isvowel ( nu )
  2.   ;; Check to see if an ASCII number is a vowel char.
  3.   ;;
  4.   ;; NOTE: This is a case insensitive check.
  5.   (and
  6.     (member
  7.       (logand nu (~ 32))
  8.       '(65 69 73 79 85 89 97))) )
  9.  
  10. (defun string-index (proc str / alst cntr)
  11.   ;; string-index
  12.   ;; Check each char of a string against a given process
  13.   ;; and return an idex number list if process returns T.
  14.       (if (= cntr '()) (setq cntr 1))
  15.       (setq len (strlen str))
  16.       (while (<= cntr len)
  17.              (if (eval (list proc (ascii (substr str cntr 1))))
  18.                (setq alst (cons cntr alst)))
  19.              (setq cntr (1+ cntr))
  20.              )
  21.       (reverse alst) )
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

JohnK

  • Administrator
  • Seagull
  • Posts: 10140
Re: [challenge] A29 : String Index
« Reply #3 on: February 28, 2022, 11:43:42 AM »
Turns out wcmatch is quick.

Code: [Select]
Elapsed milliseconds / relative speed for 2048 iteration(s):

    (STRING-INDEX-P (QUOTE ISVOWEL-P) MY...).....1297 / 3.44 <fastest>
    (STRING-INDEX-7 (QUOTE ISVOWEL-7) MY...).....4468 / 1.00 <slowest>

Code - Auto/Visual Lisp: [Select]
  1. ((lambda ( / string-index-7 isvowel-7
  2.              string-index-p isvowel-p
  3.              mystring )
  4.    (defun string-index-7 (proc str / alst cntr)
  5.      ;; string-index
  6.      ;; Check each char of a string against a given process
  7.      ;; and return an idex number list if process returns T.
  8.      (defun isvowel-7 ( nu )
  9.        ;; Check to see if an ASCII number is a vowel char.
  10.        ;;
  11.        ;; NOTE: This is a case insensitive check.
  12.        (and
  13.          (member
  14.            (logand nu (~ 32))
  15.            '(65 69 73 79 85 89 97))) )
  16.      (if (= cntr '()) (setq cntr 1))
  17.      (setq len (strlen str))
  18.      (while (<= cntr len)
  19.             (if (eval (list proc (ascii (substr str cntr 1))))
  20.               (setq alst (cons cntr alst)))
  21.             (setq cntr (1+ cntr))
  22.             )
  23.      (reverse alst) )
  24.  
  25.    (defun string-index-p (f s)
  26.      (defun isvowel-p (e)
  27.        (wcmatch e "[Aa],[Ee],[Ii],[Oo],[Uu],[Yy]"))
  28.      ( (lambda (sl i )
  29.          (while (> (setq sl (1- sl)) 0)
  30.                 (if ((eval f) (substr s sl 1))
  31.                   (setq i (cons sl i))))
  32.          i )
  33.       (1+ (strlen s))
  34.       nil))
  35.  
  36.    (setq mystring "ABCDCDEFGHIJ6789+%*/&|KLMNOPQRS 4567 %*/&|^~ qABCDrstuvwx'#()[]{ !<>;,.:? ABCD0123EFGH6789+%*/&|IJKLMNOfghijklABCDmnop8739qrstuvwxyz'#()ABCD[]{}=-0123456789+%*/&|^~!<>;,.:?")
  37.  
  38.    (benchmark
  39.      '(
  40.        (string-index-7 'isvowel-7 mystring)
  41.        (string-index-p 'isvowel-p mystring)
  42.        )
  43.      )
  44.    )
  45.  )
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

kirby

  • Newt
  • Posts: 110
Re: [challenge] A29 : String Index
« Reply #4 on: February 28, 2022, 11:45:25 AM »
One more, with testing function.

Off-topic:
Anyone know a method to print just the name of a function without the #<SUBR @000001c3dbfb5a98 ISVOWELP> business?
eval or vl-princ-to-string won't do it.

Reading the lisp file as a string and parsing would do it, but too much effort for purpose of simply showing a function name.

Code - Auto/Visual Lisp: [Select]
  1. (defun C:Test-A29 ( / MyTestFuncList MyTestStringList CNT0 MyFunc CNT1 MyString Ans)
  2. ; Test function for challenge A29
  3.  
  4. ; List of function names to be tested
  5. (setq MyTestFuncList (list
  6.         IsVowelP
  7.         IsCharP
  8.         IsNumberP
  9.         IsSpaceP
  10. ))
  11.  
  12. ; List of test strings
  13. (setq MyTestStringList (list
  14.         "apple"
  15.         "hello"
  16.         "STRAWBERRY"
  17.         "pInEaPPLe"
  18.         "ABCDCDEFGHIJ6789+%*/&|KLMNOPQRS 4567 %*/&|^~ qABCDrstuvwx'#()[]{ !<>;,.:? ABCD0123EFGH6789+%*/&|IJKLMNOfghijklABCDmnop8739qrstuvwxyz'#()ABCD[]{}=-0123456789+%*/&|^~!<>;,.:?"
  19. ))
  20.  
  21. ; Loop through functions
  22. (setq CNT0 0)
  23. (repeat (length MyTestFuncList)
  24.         (setq MyFunc (nth CNT0 MyTestFuncList))         ; get function to test
  25.  
  26.         (prompt "\n\nTesting Function <")(princ MyFunc)(prompt ">")(princ)     
  27.  
  28.         ; Loop through test strings
  29.         (setq CNT1 0)
  30.         (repeat (length MyTestStringList)
  31.                 (setq MyString (nth CNT1 MyTestStringList))     ; get string to test
  32.                 (prompt "\n  String <")(princ MyString)(prompt ">")(princ)
  33.                
  34.                 (setq Ans (String-Index-Kirby MyFunc MyString))
  35.                 (prompt "\n    --> ")(princ Ans)(princ)
  36.  
  37.                 (setq CNT1 (1+ CNT1))
  38.         ) ; close repeat
  39.  
  40.         (setq CNT0 (1+ CNT0))
  41. ) ; close repeat
  42.  
  43. )
  44.  
  45.  
  46.  
  47.  
  48. (defun String-Index-Kirby (MyFunc MyString / OutList CNT MyChar)
  49. ; A29 : String Index
  50. ; Create a function that returns the indices a string where supplied function result is true
  51. ; Input:
  52. ;       MyFunc - (name of autolisp function) function must be appropriate for operations on list items (e.g. can't test if a string is an even number)
  53. ;               examples 'IsVowelP, IsCharP, IsNumberP, IsSpaceP
  54. ;       MyString - (string) string to test
  55.  
  56. (setq OutList nil)
  57.  
  58. (if (eq (type MyString) 'STR)
  59.   (progn
  60.         (setq CNT 1)
  61.         (repeat (strlen MyString)
  62.                 (setq MyChar (substr MyString CNT 1))           ; Get character
  63.                
  64.                 (if (MyFunc MyChar)                             ; test with supplied function
  65.                         (setq OutList (cons CNT OutList))       ; add to output list if true
  66.                 )
  67.        
  68.                 (setq CNT (1+ CNT))
  69.         ) ; close repeat
  70.        
  71.         (setq OutList (reverse OutList))
  72.        
  73.   )    
  74. )
  75. OutList
  76. )
  77.  
  78.  
  79.  
  80. (defun IsVowelP (MyChar / OutVal)
  81. ; Verify if a character is a vowel (A E I O U Y)
  82. ; Input:
  83. ;       MyChar - (string) single character
  84. ; Returns:
  85. ;       T if character is a vowel (predicate function)
  86.  
  87. (if (eq (type MyChar) 'STR)             ; Verify input is a string
  88.   (progn
  89.         (if (> (strlen MyChar) 1)
  90.                 (setq MyChar (substr MyChar 1 1))       ; trim input to 1 character
  91.         )
  92.        
  93.         (if (member (strcase MyChar) (list "A" "E" "I" "O" "U" "Y"))    ; is char a vowel?
  94.                 (setq OutVal 'T)
  95.         )      
  96.   )
  97. ) ; close if
  98. OutVal
  99. )
  100.  
  101. (defun IsCharP (MyChar / OutVal)
  102. ; Verify if a character is an alpha ASCII character (A - Z, a - z)
  103. ; Input:
  104. ;       MyChar - (string) single character
  105. ; Returns:
  106. ;       T if character is a string (predicate function)
  107.  
  108. (if (eq (type MyChar) 'STR)             ; Verify input is a string
  109.   (progn
  110.         (if (> (strlen MyChar) 1)
  111.                 (setq MyChar (substr MyChar 1 1))       ; trim input to 1 character
  112.         )
  113.  
  114.         (if (<= 65 (ascii (strcase MyChar)) 90)         ; check if ascii is between A (65) and Z (90)
  115.                 (setq OutVal 'T)
  116.         )
  117.   )
  118. ) ; close if
  119. OutVal
  120. )
  121.  
  122. (defun IsNumberP (MyChar / OutVal)
  123. ; Verify if a character is a number (0 - 9).  Other symbol characters including ".", "E", "+", "-" not considered
  124. ; Input:
  125. ;       MyChar - (string) single character
  126. ; Returns:
  127. ;       T if character is a number (predicate function)
  128.  
  129. (if (eq (type MyChar) 'STR)             ; Verify input is a string
  130.   (progn
  131.         (if (> (strlen MyChar) 1)
  132.                 (setq MyChar (substr MyChar 1 1))       ; trim input to 1 character
  133.         )
  134.  
  135.         (if (<= 48 (ascii (strcase MyChar)) 57)         ; check if ascii is between 0 (48) and 9 (57)
  136.                 (setq OutVal 'T)
  137.         )              
  138.   )
  139. )
  140. OutVal
  141. )
  142.  
  143.  
  144.  
  145. (defun IsSpaceP (MyChar / OutVal)
  146. ; Verify if a character is a string
  147. ; Input:
  148. ;       MyChar - (string) single character
  149. ; Returns:
  150. ;       T if character is a space (ascii 32) (predicate function)
  151.  
  152. (if (eq (type MyChar) 'STR)             ; Verify input is a string
  153.   (progn
  154.         (if (> (strlen MyChar) 1)
  155.                 (setq MyChar (substr MyChar 1 1))       ; trim input to 1 character
  156.         )
  157.        
  158.         (if (equal MyChar " ")          ; is char a space?
  159.                 (setq OutVal 'T)
  160.         )
  161.   )
  162. ) ; close if
  163. OutVal
  164. )
  165.  
  166.  

JohnK

  • Administrator
  • Seagull
  • Posts: 10140
Re: [challenge] A29 : String Index
« Reply #5 on: February 28, 2022, 12:54:10 PM »
One more, with testing function.

Off-topic:
Anyone know a method to print just the name of a function without the #<SUBR @000001c3dbfb5a98 ISVOWELP> business?
eval or vl-princ-to-string won't do it.

Reading the lisp file as a string and parsing would do it, but too much effort for purpose of simply showing a function name.
--->%

Looking quickly, I dont think it's possible the way you have your test structured. I would pass the function calls to your test function instead of assembling the lists like this (inside the test function):
Code - Auto/Visual Lisp: [Select]
  1. ; List of function names to be tested
  2. (setq MyTestFuncList (list
  3.         IsVowelP
  4.         IsCharP
  5.         IsNumberP
  6.         IsSpaceP
  7. ))
  8.  
  9. ; List of test strings
  10. (setq MyTestStringList (list
  11.         "apple"
  12.         "hello"
  13.         "STRAWBERRY"
  14.         "pInEaPPLe"
  15.         "ABCDCDEFGHIJ6789+%*/&|KLMNOPQRS 4567 %*/&|^~ qABCDrstuvwx'#()[]{ !<>;,.:? ABCD0123EFGH6789+%*/&|IJKLMNOfghijklABCDmnop8739qrstuvwxyz'#()ABCD[]{}=-0123456789+%*/&|^~!<>;,.:?"
  16. ))
TheSwamp.org (serving the CAD community since 2003)

Donate to TheSwamp.org

ribarm

  • Gator
  • Posts: 2747
  • Marko Ribar, architect
Re: [challenge] A29 : String Index
« Reply #6 on: February 28, 2022, 01:24:38 PM »
Here is one way :

Code: [Select]
: (setq isvowel nil)
nil
: !isvowel
nil
: (setq a (defun isvowel ( str ) (wcmatch str "[Aa],[Ee],[Ii],[Oo],[Uu],[Yy]")))
ISVOWEL
: !a
ISVOWEL
: (princ a)
ISVOWELISVOWEL
: (print a)

ISVOWEL ISVOWEL
: (prin1 a)
ISVOWELISVOWEL
: (isvowel "Marko Ribar")
nil
: (isvowel "MarkoRibar")
nil
: (isvowel "a")
T
: (isvowel "A")
T
: (isvowel "E")
T
: (isvowel "g")
nil
: (isvowel "G")
nil
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

kirby

  • Newt
  • Posts: 110
Re: [challenge] A29 : String Index
« Reply #7 on: February 28, 2022, 01:47:33 PM »
(Still off topic)

Thanks Marko, that worked.  Just too convoluted to use in practice.

Code - Auto/Visual Lisp: [Select]
  1. (defun C:Test-FuncName ()
  2.  
  3. (setq aaa
  4.         (defun xyzzy (MyChar / OutVal)
  5.         ; Verify if a character is a vowel (A E I O U Y)
  6.         ; Input:
  7.         ;       MyChar - (string) single character
  8.         ; Returns:
  9.         ;       T if character is a vowel (predicate function)
  10.  
  11.         (if (eq (type MyChar) 'STR)             ; Verify input is a string
  12.           (progn
  13.                 (if (> (strlen MyChar) 1)
  14.                         (setq MyChar (substr MyChar 1 1))       ; trim input to 1 character
  15.                 )
  16.  
  17.                 (if (member (strcase MyChar) (list "A" "E" "I" "O" "U" "Y"))    ; is char a vowel?
  18.                         (setq OutVal 'T)
  19.                 )      
  20.           )
  21.         ) ; close if
  22.         OutVal
  23.         )
  24. )
  25.  
  26. (setq MyString "apple")
  27.  
  28. (prompt "\nFunction Name = ")(princ aaa)
  29. (prompt "\n  Input = ")(princ MyString)
  30.  
  31. (setq Ans (xyzzy mystring))
  32. (prompt "\n  Output = ")(princ Ans)
  33. )
  34.  


Command: TEST-FUNCNAME

Function Name = XYZZY
  Input = apple
  Output = T