Finding values in a list..

Discussion in 'AutoCAD' started by Rick Keller, Nov 15, 2004.

  1. Rick Keller

    Rick Keller Guest

    I have a file... in the file are lines
    example the actual file has 479 lines:

    BCW 0
    BCT 0
    BCS 0
    BCP 0
    BCM 0
    BCL 0
    BCJ 0
    BCG 0
    BCC 0

    I can read the file and turn it into a list like so:

    ("BCC 0" "BCG 0" "BCJ 0" "BCL 0" "BCM 0" "BCP 0"
    "BCS 0" "BCT 0" "BCW 0")


    How do I search through the list for a certain string?

    The letter prefix will stay the same but the zero will be a counter so it
    will change.

    Would it be easier to make them dotted pairs?

    What I am doing is...

    1. Reading the file
    2. Searching for a certain line.
    3. Increasing the number on that line by 1.
    4. Writing the file back with the new line in place of the old one.

    Thanks
    Rick
     
    Rick Keller, Nov 15, 2004
    #1
  2. Rick Keller

    T.Willey Guest

    You can use (member.

    Tim
     
    T.Willey, Nov 15, 2004
    #2
  3. I'd use the vl-position or member functions.
     
    Jason Piercey, Nov 15, 2004
    #3
  4. once you have the list, loop through it and use wcmatch to find something.
    (wcmatch "this is good" "this is*") gives a true back.

    Then sub in a new item into the list and save back.

    You could even do this all in one loop, fakish code...
    (defun mylisp (key new-val / )
    read lines of text file to text-list
    (foreach item text-list
    (if (wcmatch item (strcat key "*"))
    (setq new-item (strcat key " " (itoa new-val)))
    new-list (cons item new-list))
    )
    (setq new-list (cons item new-list))
    )
    )
    write new-list to file
    )

    You really need to gather some subroutines together for the tasks of reading and writing lists to file and back.
    Otherwise its just splitting things up and reassembling to get new list.
    You can see the delimiter is very important for stuff like this, use || or something very unique and the parsing is so
    much easier.



    "Rick Keller" <>
    |>I have a file... in the file are lines
    |>example the actual file has 479 lines:
    |>
    |>BCW 0
    |>BCT 0
    |>BCS 0
    |>BCP 0
    |>BCM 0
    |>BCL 0
    |>BCJ 0
    |>BCG 0
    |>BCC 0
    |>
    |>I can read the file and turn it into a list like so:
    |>
    |>("BCC 0" "BCG 0" "BCJ 0" "BCL 0" "BCM 0" "BCP 0"
    |>"BCS 0" "BCT 0" "BCW 0")
    |>
    |>
    |>How do I search through the list for a certain string?
    |>
    |>The letter prefix will stay the same but the zero will be a counter so it
    |>will change.
    |>
    |>Would it be easier to make them dotted pairs?
    |>
    |>What I am doing is...
    |>
    |>1. Reading the file
    |>2. Searching for a certain line.
    |>3. Increasing the number on that line by 1.
    |>4. Writing the file back with the new line in place of the old one.
    |>
    |>Thanks
    |>Rick
    |>

    James Maeding
    jmaeding at hunsaker dot com
    Civil Engineer/Programmer
     
    James Maeding, Nov 15, 2004
    #4
  5. Rick Keller

    Rick Keller Guest

    I guess I am doing this out of order.

    In order for that to work I'll need to know the actual # that follows the
    prefix.
    So I'm going to need to find the line in the file first... read it then find
    it in the list... etc

    I'll have to re-think this.

    Thanks
    Rick
     
    Rick Keller, Nov 15, 2004
    #5
  6. Rick Keller

    Tom Smith Guest

    Per James' remarks on the delimiter, I'd use dotted pairs for this. That's
    exactly what you have, after all, pairs of things, so it would seem a more
    natural approach. Lisp has built-in tools for handling association lists,
    which ought to eliminate the need for programming a parser. Otherwise you're
    going to spend all your time pulling strings apart and putting them back
    together again. Then James' code would reduce to:

    (defun mylisp (key new-val / data-list)
    ;; read lines of text file to data-list
    ;;e.g. '((BCC . 0) (BCG . 0) (BCJ . 0) etc.)
    ;;then alter data-list
    (setq data-list (subst (cons key new-val) (assoc key data-list) data-list))
    ;;write data-list to file
    )
     
    Tom Smith, Nov 15, 2004
    #6
  7. Rick Keller

    Rick Keller Guest

    I was thinking dotted pairs would be easier since you can search for the
    prefix and it would return both.
    What format would my text file need to be in?

    BCC.0
    BCG.0
    BCJ.0

    Like that?

    I'll approach it again in the morning.

    Thanks for your help.
    Rick
     
    Rick Keller, Nov 15, 2004
    #7
  8. Rick Keller

    Tom Smith Guest

    What format would my text file need to be in?

    Good question. I was thinking use the actual association groups

    (BCC . 0)
    (BCG . 0)
    (BCJ . 0)

    Then you could read-line them in as text strings e.g. "(BCC . 0)" and
    convert them to lists via (read "(BCC . 0)").

    But writing them back to the file in that form might be a nuisance, I guess
    you'd want a list-to-string converter function.
     
    Tom Smith, Nov 15, 2004
    #8
  9. Your text file can be most anything, as long as it is consistent. Comma or
    tab delimited would get my vote.

    --
    R. Robert Bell


    I was thinking dotted pairs would be easier since you can search for the
    prefix and it would return both.
    What format would my text file need to be in?

    BCC.0
    BCG.0
    BCJ.0

    Like that?

    I'll approach it again in the morning.

    Thanks for your help.
    Rick
     
    R. Robert Bell, Nov 15, 2004
    #9
  10. Rick Keller

    Rick Keller Guest

    Ok... Here is what I have come up with.
    I need to embellish on the "what ifs" but basically it works.
    I know there are probably easier ways and I am always looking for
    suggestions if anyone
    feels the need.

    This is my first time working with files & lists.

    File format is:

    BCC.0
    BCG.0
    BCJ.0
    BCM.0

    Thanks for all the help.
    Rick


    ;;---------------------------Find the line in the
    file----------------------------------
    (setq prefix "BCM")
    (setq whatline 1)
    (setq a (open "m:/catalog/catnum.txt" "r"))
    (setq len (strlen prefix))
    (setq str "temp")

    (while (/= (substr str 1 len) prefix)
    (setq str (read-line a))
    (if (= (substr str 1 len) prefix)
    (setq gotit str)
    (setq whatline (1+ whatline))
    )
    )
    (CLOSE a)
    ;;--------------------------------------------------------------------------------------


    ;;--------------------------------------------------------------------------------------
    ;;-----------------------create the list from the
    file----------------------------------
    ;;--------------------------------------------------------------------------------------
    (setq mfile (open "m:/catalog/catnum.txt" "r"))
    (setq entire_file nil)
    (while (setq rd_lin (read-line mfile))
    (setq entire_file (cons rd_lin entire_file))
    )

    (close mfile)
    ;;--------------------------------------------------------------------------------------

    ;;-------------------do the
    math--------------------------------------------------------
    (setq number-length (- (strlen str) 4))

    (setq new_string_num (1+ (fix (atof (substr str 5 number-length)))))
    (setq new_str (strcat (substr str 1 4) (rtos new_string_num 2 0)))

    (setq n_list (subst new_str str entire_file))
    ;;--------------------------------------------------------------------------------------

    ;;-------------------------backup old
    file----------------------------------------------

    (if (= (findfile "m:/catalog/catnum.bak") nil)
    (vl-file-rename
    "m:/catalog/catnum.txt"
    "m:/catalog/catnum.bak"
    )
    (progn
    (vl-file-delete "m:/catalog/catnum.bak")
    (vl-file-rename
    "m:/catalog/catnum.txt"
    "m:/catalog/catnum.bak"
    )
    )
    )
    ;;-------------------------------------------------------------------------------------

    ;;-------------------------write the new
    file-------------------------------------------

    (setq mfile (open "m:/catalog/catnum.txt" "w"))
    (setq ctr -1)
    (repeat
    (setq ctr (- (length n_list) 1))
    (while (> ctr 0)
    (setq output (nth ctr n_list))
    (write-line output mfile)
    (setq ctr (- ctr 1))
    )
    )
    (close mfile)
    ;;-------------------------------------------------------------------------------------
     
    Rick Keller, Nov 16, 2004
    #10
  11. Rick Keller

    John Uhden Guest

    This is a strange approach...
    Command: (setq a '("BCC 1" "BCG 2" "BCJ 3" "BCL 4" "BCM 5"))
    returns:
    ("BCC 1" "BCG 2" "BCJ 3" "BCL 4" "BCM 5")

    Command: (setq b (mapcar '(lambda (x)(apply 'cons (read (strcat "(" x ")"))))
    a))
    returns:
    ((BCC . 1) (BCG . 2) (BCJ . 3) (BCL . 4) (BCM . 5))

    Command: (cdr (assoc (read "bcm") b))
    returns:
    5

    Yeah, maybe you oughta organize the file a little better.
     
    John Uhden, Nov 17, 2004
    #11
  12. Rick Keller

    Doug Broad Guest

    Yeah,

    Just format like

    '(
    ( "B" . 3)
    ("A" . 0)
    ......
    ))


    and use

    (setq lst (load "file") to bring it in and use it and store it with

    (setq fh (open "c:\\arch\\dcb\\test3.txt" "w"))
    (princ "'(" fh )
    (foreach n lst
    (prin1 n fh)
    ;(princ "\n" fh) ;;optional break at elements
    )
    (princ ")" fh)
    (close fh)
     
    Doug Broad, Nov 17, 2004
    #12
  13. My 2 cents:
    CSV (like export from Excel)

    BCC;0
    BCG;0
    BCJ;0

    You can have numbers with decimal delimiter
    in the string : "BCC;1,234.456"
    or in Euro form: "BCC;1.234,456"

    To get a list from a string:

    ; delimiter = 1 character
    (defun ALE_String2List (InpStr CarDlm / SttPos EndPos TmpLst)
    (setq
    CarDlm (ascii CarDlm) SttPos 0
    EndPos (vl-string-position CarDlm InpStr)
    )
    (while EndPos
    (setq
    TmpLst (cons (substr InpStr (1+ SttPos) (- EndPos SttPos)) TmpLst)
    SttPos (1+ EndPos) EndPos (vl-string-position CarDlm InpStr SttPos)
    )
    )
    (reverse (cons (substr InpStr (1+ SttPos)) TmpLst))
    )

    (ALE_String2List "BCC;0" ";")
    (ALE_String2List "BCC;1,234.456" ";")

    --

    Marc'Antonio Alessi
    http://xoomer.virgilio.it/alessi
    (strcat "NOT a " (substr (ver) 8 4) " guru.")

    --
     
    Marc'Antonio Alessi, Nov 17, 2004
    #13
  14. Rick Keller

    Rick Keller Guest

    Thanks...John & Doug

    I have it working for what I want it to do.

    I realized I was trying to create step 2 before I created step 1.

    I switched to finding the line in the file first and reading it.

    This gave me the value to search for in the list.

    The rest was kind of easy just manipulate the string & rewrite it to the
    list.

    I did change my format of the lines in the file from
    BCC 1
    to
    BCC.1
    I don't know what possessed me to add all of the spaces in the first place.

    What this program will do is keep track of a catalog of sections. This is
    the portion
    that will automatically number the blocks and wblock out the selected
    entities and
    place them in a directory structure categorized by the 3 letter designation
    each letter
    being a subdirectory of the previous.

    Also... I tried (setq lst (load "my file")) but it read each line as nil
    and returned nil.

    Thanks again everyone.
    Rick
     
    Rick Keller, Nov 17, 2004
    #14
  15. Rick Keller

    Doug Broad Guest

     
    Doug Broad, Nov 17, 2004
    #15
  16. Rick Keller

    Doug Broad Guest

    Rick,
    You're welcome. The reason load didn't work for you is that
    you need to specify the file extension if it is not a lisp file (.lsp assumed).
    You also need to provide the path if the file is not on the search path.

    As a general rule, I would discourage you from using periods as your
    delimiter. It plays hell with real numbers. Use commas instead.

    Regards,
    Doug

    Sorry for blank return. Anne, please delete.
     
    Doug Broad, Nov 17, 2004
    #16
  17. Rick - Unless you are dealing with a very large amount of data,
    I would suggest you just read and write the entire list from/to a
    file, and search/replace in memory.

    ;; Write a list to a file in a form that allows it to
    ;; be read back using the (load) function:
    ;;
    ;; Note: This will round floating point values
    ;; in the same way the print, princ and prin1
    ;; functions do, and cannot be used to persist
    ;; opaque data types like entity names, file
    ;; handles, selection sets, etc.

    (defun write-simple-list (lst file / fh)
    (setq fh (open file "w"))
    (prin1 (list 'quote lst) fh)
    (close fh)
    )

    ;; Read a list from a file:

    (defun read-list (file)
    (load file)
    )
     
    Tony Tanzillo, Nov 17, 2004
    #17
  18. Rick Keller

    Doug Broad Guest

    Even better. Thanks Tony.
     
    Doug Broad, Nov 17, 2004
    #18
  19. Rick Keller

    Doug Broad Guest

    Rick,
    Don't think you're reading my posts closely.

    Here is a sample of your file:
    BCC.1
    BCG.1
    BCJ.1
    BCL.1
    BCM.1
    BCP.1

    Here was my suggested file format:

    '(
    ("BCC" . 1)
    ("BCG" . 1)
    ("BCJ" . 1)
    )

    If you stick with your format, then my method won't
    work. The load format requires a valid formatted list.
    The dotted list must have spaces on each side of the dot.
    The parentheses, quotes, and quotation marks are critical.

    If you've got it working to your satisfaction, then I'd stick
    with it.

    Best wishes,
    Doug Broad
     
    Doug Broad, Nov 17, 2004
    #19
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.