AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

[lib] SimpleArray - short, fast, string array functions - v3
Goto page 1, 2, 3, 4, 5  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
infogulch



Joined: 27 Mar 2008
Posts: 353

PostPosted: Mon Aug 25, 2008 4:24 am    Post subject: [lib] SimpleArray - short, fast, string array functions - v3 Reply with quote

[Edit]
This is version Beta3, and I've made lots of changes, some of which may not be reflected in these (already sparse) docs. This has been released early because of the proddings of bmcclure. In light of that, some code is still messy (i.e. I forbid anyone from looking at SA_Del() Razz ) and not completely tested, so please gimme a couple days before you start code-bashing my lib. Razz Very Happy
[/Edit]

SimpleArray is a single variable list/array editing function library focused on speed and simplicity. It does not loop, parse or split the array when working with it, and all the functions can finish while executing less than 20 total lines of code.

I must credit olegbl for his excellent AHKArray library, which is similar in concept, but unfortunately not compatible. Since SA is 'simple' I won't be adding some advanced features such as those found in AHKA, so if you are looking for advanced features, I must refer you to olegbl's thread. However, I am open to suggestions and if you have a feature / improvement idea that fits in the bounds of the title, it would be very welcome. Very Happy

Note: it is still to be tested further, so please be careful with your data! If you find any bugs I would very much appreciate it reported! Smile

[About]
  • Lib: These functions are library compatible, so you can save them in one of your lib folders as SA.ahk and they will be accessible without using #Include.
  • Number Index: (param name Idx may only be a number)
    For values above 0, a position relative to the beginning of the array with an index of 1. So the first element is '1', the second '2' etc.
    For values below 0, a position relative to the end of the array with an index of -1. So the last element is '-1', second to last '-2', etc.
    Zero is not used, do not pass 0 as an index. (Note that this is different from AHKA)
    If you want to add a value at the end of the array with SA_Set() use '+' as the first character and the number following will be counted as an offset from the end of the array. This allows you to add it arbitrarily farther than the end. (Note that the default index param is '+1' so you can add it to the end without specifying a number yourself)
  • Name Index: (param name nIdx May be either a number or a name.)
    A valid name is any non-blank, non-number string.
    If an element has a name, you can reference by it's name instead of element index.
  • Functions:
    SA_Set( Array, Val, [nIdx="+1", Insert=false, giveName=""] ) ~ returns the new array with Val set to nIdx. If you pass a name for nIdx, the name will be preserved unless you pass something else to giveName. If you pass a number for nIdx, the element's name (if any) will be discarded. (this behaviour may be modified)
    SA_Get( Array, nIdx1=1, nIdx2="", nIdx3="", nIdx4="", nIdx5="" ) ~ returns the array element at nIdx1. Also retrieves nested arrays' elements. If you want to retrieve values more than 5 elements deep, add more params numbered sequentially.
    SA_Del( Array, nIdxFm, nIdxTo="", Count=0 ) ~ returns the new array with elements from nIdxFm to nIdxTo removed. OR you can pass nIdxFm and Count, in which case it deletes Count number of elements starting at nIdxFm
    SA_Trim( Array, nIdxFm, nIdxTo=-1 ) ~ returns the new array with everything outside of nIdxFm to nIdxTo removed.
    SA_Len( Array ) ~ returns the length of the array
    SA_IdxName( Array, Name ) ~ returns the index of Name in Array as a number
    SA_NameIdx( Array, Idx ) ~ returns the name (if any) of Idx as a string
    SA_ValidName( x ) ~ used internally, returns true if the value passed is acceptable as a name
    [i]SA_Enc( Array )[/i] ~ used internally, returns a value ready to be used as an element
    [i]SA_Dec( Array )[/i] ~ used internally, returns a value ready to be used outside the array
    SA_EncRE( x ) ~ used internally, escapes a string for use in RegEx


[Code] Download
Code:


[Demonstration]
Code:
; later


[ToDo]
    Document speed for different sizes of arrays.
    Document the functions more fully.
    Document arrays inside arrays.
    More consistent ErrorLevel


[Revision History]

    _________________
    A great Beginner's Tutorial


    Last edited by infogulch on Tue Oct 28, 2008 4:28 pm; edited 4 times in total
    Back to top
    View user's profile Send private message
    Laszlo



    Joined: 14 Feb 2005
    Posts: 4474
    Location: Boulder, CO

    PostPosted: Mon Aug 25, 2008 4:49 am    Post subject: Reply with quote

    Nice! You could get some more ideas in the 3.5 years old List manipulation functions thread. Lists are one dimensional arrays, represented as strings, with their elements separated by specific delimiters. Since the original library was written AHK evolved quite a bit. E.g. Regular Expressions could greatly reduce the code size and improve the speed.
    Back to top
    View user's profile Send private message
    olegbl



    Joined: 13 Dec 2006
    Posts: 48

    PostPosted: Mon Aug 25, 2008 7:32 am    Post subject: Reply with quote

    Cool! I like it! Good job on making it fast!
    (I know that takes a ton of work =P)
    Are you using a delimetered (|) string to store it (with encoding)?
    If you want, I can work on some conversion function between our libs =)

    Laszlo wrote:
    Nice! You could get some more ideas in the 3.5 years old List manipulation functions thread. Lists are one dimensional arrays, represented as strings, with their elements separated by specific delimiters. Since the original library was written AHK evolved quite a bit. E.g. Regular Expressions could greatly reduce the code size and improve the speed.

    Wow, I never saw the List Manipulation Functions thread when I was making the array lib haha. This looks very similar in concept, thanks for bringing it up Laszlo!
    Back to top
    View user's profile Send private message
    infogulch



    Joined: 27 Mar 2008
    Posts: 353

    PostPosted: Mon Aug 25, 2008 2:59 pm    Post subject: Reply with quote

    Thank you Lazlo and olegbl! I appreciate your support. Smile

    Ah, the List Manipulation Functions, I will definitely have to take a close look at those, thanks Lazlo. Actually, I was trying to avoid RegEx for speed purposes, since the most demanding commands in a function are StringReplace*2, StringGetPos*2 and SubStr()*2. But if you can convince me that RegEx would help speed, I'd be more than willing to attempt it. Very Happy
    Quote:
    Lists are one dimensional arrays, represented as strings, with their elements separated by specific delimiters.
    I need a more descriptive definition of an "Array" as used in SA, thanks for reminding me, that's a good start. Razz

    Yes olegbl, a SA array is a string with the pipe char as a delimiter between elements. ("|") It also uses a special, complex encoding method I invented myself for when a user passes a value with that character to be an element. ("%d" for the delimiter, and "%e" for the encoding character: "%". Soooo complex, omg. LOLOL, jk) (see the SA_Enc/Dec functions) Because of this, you can pass one array as a value into another, and it will automatically encode it as a value. You can then get it back out as an array with no problems. You can even make it several arrays deep, and still get original values back out. (What would this be called? "Jagged arrays"?) One problem with this (vs. say using [ ] to define an array inside another) is that every time it's encoded, the string expands by 2*number of total | and % chars.

    I noticed in the List manipulation thread Lazlo pointed out the built-in ahk commands If In / Contains and because those are comma delimited, I am seriously considering changing the delimiter from "|" to ",", though a simple StringReplace would make it compatible. I also had the idea to have a global delimiter variable, but I didn't want any problems with multiple included scripts setting that variable and having compatibility issues.

    Wow, I feel long winded today. Yes olegbl I would love for you to make some conversion functions between our libraries. I start college today and will be rather preoccupied for some time myself, so that would be very much appreciated. Very Happy Keep in mind though, that this lib may change frequently (at least initially), so you may want to wait a while.

    Smile
    _________________
    A great Beginner's Tutorial
    Back to top
    View user's profile Send private message
    olegbl



    Joined: 13 Dec 2006
    Posts: 48

    PostPosted: Mon Aug 25, 2008 7:00 pm    Post subject: Reply with quote

    Yup, I was thinking of waiting for a settled format, I remember it took me months before I settled on something XD (Though I'm also going to college in about a month heh)
    For your encoding/decoding format, do the %e, %d characters get recoded when included?
    Code:
    insert "one2|one3" at #2 of "one|two|three"
    one|one2%done3|two|three
    insert "one|one2%done3|two|three" at #2 of "a|b|c"

    Would that make:
    Code:
    a|one%done2%done3%dtwo%dthree|b|c
    ; OR
    a|one%done2%%done3%dtwo%dthree|b|c

    If it's the first case, you're limited two 2D, if second, "infinite" dimensions.
    You're making a very good system though, mine is a lot more burdensome and over-complicated (especially since I settled on HEXing) XD
    Also for the system, back in the day I though about this option:
    Code:
    ;Array = [one,two,[three1,three2,[three3i,three3ii],three4],four]
    ;Actual Format = |one|two||three1||three2|||three3i|||three3ii||three4|four

    Or, replace multiple bars with : |1, |2, |3, etc...
    The problem comes with:
    Code:
    [1,[2],[3]]
    It'll think it's
    Code:
    [1,[2,3]]
    ...
    Anyway, I think the Enc Dec thing works fine (as long as it re-encodes previously encoded characters (& decodes previously decoded characters). Good job on coming up with it =D
    Best of luck on the project! =)


    Last edited by olegbl on Tue Oct 14, 2008 6:16 pm; edited 1 time in total
    Back to top
    View user's profile Send private message
    defrostedchemist



    Joined: 09 Sep 2008
    Posts: 5

    PostPosted: Tue Sep 09, 2008 10:25 pm    Post subject: Reply with quote

    Code:

    ;Wow, I really like these array functions!
    ;I have two questions,
    ;I am currently using your array functions to do the following:

    ;This is my array.
    TimerArray = 0|0|0|0|0|0|0|0|0|0|0|0

    ;This is my timer that preforms the action "Minute" every minute.
    Settimer, Minute, 60000
    Return

    ;This is the action "Minute" that uses your functions to operate on TimerArray.
    Minute:
    NumberofMinutes:=SA_Get(TimerArray,1)
    NumberofMinutes+=1
    TimerArray:=SA_Set(TimerArray,NumberofMinutes,1)
    return
    ;So far this will increase the first index of the timer array by 1 each minute.
    ;So now the first question.
    ;How do I make one function that can do this in one step?
    ;IE:  Array:=SA_Set({Array to modify}, {Current Array Value + 1}, {Index to replace})

    ;And second question, how do I preform this opperation on a range of the array.
    ;IE:  Array:=SA_Set({Array to modify}, {Current Array Value + 1}, {Begining of range}, {End of range})

    ;I am asking this because I have a looped process.
    Loop{
    ;Task that varies in completion time.
    Counter += 1
    }
    ;So using: Array:=SA_Set({Array to modify}, {Current Array Value + 1}, {Begining of range}, {End of range})
    ;I could do: TimerArray:=SA_Set(TimerArray, {Current Array Value + 1}, 0, Counter)
    ;So on the first loop the timer would add +1 each minute to the first index.
    ;On the second loop the timer would add +1 each minute to index 1 and 2.
    ;On the tenth loop the timer would add +1 each minute to indexes 1 through 10.

    ;I tried to combine and modify your SA_Get,SA_Set, and the range portion of the
    ;SA_Trim functions to preform this task, but got really confused in the process.
    ;(I'm very new to AHK. This is my first post.)

    ;ANY help you could provide with this would be very much apreaciated!!!
    Back to top
    View user's profile Send private message
    infogulch



    Joined: 27 Mar 2008
    Posts: 353

    PostPosted: Tue Sep 09, 2008 10:50 pm    Post subject: Reply with quote

    defrostedchemist wrote:
    ;Wow, I really like these array functions!
    Thanks!

    defrostedchemist wrote:
    ;How do I make one function that can do this in one step?
    Code:
    SA_Set(TimerArray, SA_Get(TimerArray, 1)+1, 1)
    Is this what you're looking for?

    defrostedchemist wrote:
    ;So on the first loop the timer would add +1 each minute to the first index.
    ;On the second loop the timer would add +1 each minute to index 1 and 2.
    ;On the tenth loop the timer would add +1 each minute to indexes 1 through 10.

    Unfortuneately, there is currently no built-in way to work on a range of an array. But try this, I think it's something like what you're asking.
    Code:
    ;Untested:
    loop 10
        loop %A_Index% ;the index of the outer loop
            SA_Set(TimerArray, SA_Get(TimerArray, A_Index)+1, A_Index)   ;this uses the index of the inner loop


    Let me know if that works or not.

    Smile
    _________________
    A great Beginner's Tutorial
    Back to top
    View user's profile Send private message
    bmcclure



    Joined: 24 Nov 2007
    Posts: 766

    PostPosted: Wed Oct 08, 2008 6:12 pm    Post subject: Reply with quote

    Great functions! I'm going to give them a try for some of my simpler arrays in SteamLab and see how it works.

    I would like to see how this compares to AHKArray (which I've been using in SteamLab) for larger, multi-dimensional arrays. Do we know how much faster the encoding is here than AHKArray's hexing?

    Has this been tested on large/deep arrays to still have a good speed advantage?
    _________________
    Ben

    My Trac projects
    My Wiki
    [Broken] - My music
    Back to top
    View user's profile Send private message
    olegbl



    Joined: 13 Dec 2006
    Posts: 48

    PostPosted: Wed Oct 08, 2008 8:37 pm    Post subject: Reply with quote

    bmcclure wrote:
    I would like to see how this compares to AHKArray (which I've been using in SteamLab) for larger, multi-dimensional arrays. Do we know how much faster the encoding is here than AHKArray's hexing?


    I think I can answer that.
    Considering SimpleArray encodes only delimiters and also doesn't need a complex parse function to access multi-dimensional arrays, it should (well, I don't know for sure, but I'm pretty sure), be *a lot* faster than AHKA. If I could use the comparison, SimpleArray would be like Unix: fast, compact, efficient while AHKA would be like Windows: slow, cumbersome, tons of features.
    Though infogulch would be the real expert on the speed portion, so correct me if I'm wrong. =)


    Last edited by olegbl on Tue Oct 14, 2008 6:16 pm; edited 1 time in total
    Back to top
    View user's profile Send private message
    bmcclure



    Joined: 24 Nov 2007
    Posts: 766

    PostPosted: Wed Oct 08, 2008 9:20 pm    Post subject: Reply with quote

    Thanks; That's what I figured.

    I really love the advanced functions of AHKA, however, and have never had a big problem with my apps running slow.

    A lot of extra speed can never hurt though.

    The only thing that's really missing from SimpleArray that I would love to see is a simple SA_Find function that locates the index of the first instance of a value in an array.

    Perhaps something like SA_Find(Array, Value, Pos) where Pos could be the positive or negative index number to start searching forwards or backwards from?

    I know that it would probably be the slowest function included with SA, but in my case (and I'm assuming many others), I am always trying to figure out the index of a particular value in a dynamic array and this would be a great help.
    _________________
    Ben

    My Trac projects
    My Wiki
    [Broken] - My music
    Back to top
    View user's profile Send private message
    infogulch



    Joined: 27 Mar 2008
    Posts: 353

    PostPosted: Sat Oct 11, 2008 2:28 am    Post subject: Reply with quote

    Hey guys!

    That's a good idea, bmcclure. So I'm implementing element names, and ways to get their indexes. I'll probably overload most of the functions, allowing you to set and get nested arrays with one function, referencing either by name or index. It will still be fast, and I can keep my "no looping" staus. Wink

    Thanks for answering olegbl. Yeah, that's about as well as I could explain it. Smile

    Actually, as I'm going through and rewriting I'm actually shortening these functions quite a bit. E.g. sa_set, it was ~16 lines, and I shortened it to 11. And get went from 10 to 6. Hopefully shorter = faster in this instance. Razz So maybe the name addition won't add much more overhead .

    I wanted to post something here just to let you guys know I'm not abandoning this. Wink

    Smile
    _________________
    A great Beginner's Tutorial
    Back to top
    View user's profile Send private message
    bmcclure



    Joined: 24 Nov 2007
    Posts: 766

    PostPosted: Sat Oct 11, 2008 2:48 am    Post subject: Reply with quote

    Sounds cool! By names do you mean it will support named indexes?

    If so, and with the lookup functions you're working on, I'm very excited! It could be exactly what I'm looking for for at least some of the SteamLab arrays, and if there is still a performance benefit over AHKA that would be an added bonus of maybe speeding up the application a bit.

    Looking forward to the next code update Smile
    _________________
    Ben

    My Trac projects
    My Wiki
    [Broken] - My music
    Back to top
    View user's profile Send private message
    CannedCheese



    Joined: 21 May 2008
    Posts: 120

    PostPosted: Mon Oct 13, 2008 10:20 pm    Post subject: Reply with quote

    This looks cool and I will definitely be playing with it. My only suggestion would be to add a second parameter so that one can optionally pass a delimiter (obv. I will add this myself, and I know you want to keep things simple and fast, but I'm not sure how much a delimiter change will slow things down). I often have to import user entered data from a text file, and some of the entered data can contain the pipe "|" character. I'd like the option to switch to a character that they can't enter, such as A_Tab or the standard comma, or something. Again, this is something that I should be able to implement for myself, but as I'm not sure it would really slow down the code any, I thought I'd suggest it.
    Back to top
    View user's profile Send private message
    bmcclure



    Joined: 24 Nov 2007
    Posts: 766

    PostPosted: Tue Oct 14, 2008 6:11 pm    Post subject: Reply with quote

    Your data can contain the pipe character; that's the best part about it. The data you pass into the functions is encoded, so pipes will be encoded and decoded correctly at each level.

    That is my understanding, at least; correct me if I'm wrong.
    _________________
    Ben

    My Trac projects
    My Wiki
    [Broken] - My music
    Back to top
    View user's profile Send private message
    olegbl



    Joined: 13 Dec 2006
    Posts: 48

    PostPosted: Tue Oct 14, 2008 6:15 pm    Post subject: Reply with quote

    Actually, from what infogulch said, I understand it as the delimiter being encoded rather than the pipe character. Which is much much more efficient.
    Back to top
    View user's profile Send private message
    Display posts from previous:   
    Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
    Goto page 1, 2, 3, 4, 5  Next
    Page 1 of 5

     
    Jump to:  
    You can post new topics in this forum
    You can reply to topics in this forum


    Powered by phpBB © 2001, 2005 phpBB Group