Search code examples
arrayszsh

zsh array implementation (not asociative array)


I am completly new to zsh, come to it after discovering that macosx on catalina highly push to it. While I got a bit disoriented at first, I managed to rampup my knowledge of it, and so far I am about happy with it. Yet I bump into an issue that I can't solve with a trivial setopt, so may be one out there can help me.

The problem I got is with regular indexed arrays, like the following snippet

a[1]=1;         echo n=${#a[@]} ${a[@]}
a[1000000]=1;   echo n=${#a[@]} ${a[@]}
a[100000000]=1; echo n=${#a[@]} ${a[@]}

With bash (or ksh) I got this

$ a[1]=1;         echo n=${#a[@]} ${a[@]}
n=1 1

$ a[1000000]=1;   echo n=${#a[@]} ${a[@]}
n=2 1 1

$ a[100000000]=1; echo n=${#a[@]} ${a[@]}
n=3 1 1 1

With zsh I got this

PW$ a[1]=1;         echo n=${#a[@]} ${a[@]}
n=2 1

PW$ a[1000000]=1;   echo n=${#a[@]} ${a[@]}
n=1000001 1 1

PW$ a[100000000]=1; echo n=${#a[@]} ${a[@]}
n=100000001 1 1 1

Note that the off by one in n= is due to my setopt ksharrays, yet what's bugs me is that n= to a huge number even though I got very few entries in the array, that lead me to thin zsh indexed arrays are non-sparse, but then why ${a[@]} don't expanse them all, it somehow have a notion of sparsitude. Beside the last line takes an incredible amount of time, a kind of denial of service :) may all workstation is hang.

One could argue that going indexed array with that big of an index on an interpreted language could be wrong up front, yet bug happens, and getting a buggy index (huge) can simply hog your computer instead of gently tells you are way off base :)

So my question, what option (setopt) should I use to get indexed sparse array?

Any helps appreciated.


Solution

  • I don't work with zsh so fwiw ...

    A bit of research shows zsh array indexes are sequential from 1 to # (number of elements in array).

    I couldn't find any references to populating a sparse array (eg, index = 1, 1000000 or 10000000).

    Under zsh I ran:

    $ a[1000000]=1
    
    $ echo "${#a[@]}"
    1000000
    
    $ echo "${a[@]}"
    1                                          # prints out a **LOT** of blank
    ....                                       # lines in my terminal with
                   1                           # the last line showing the last '1' somewhere out in the middle of the terminal
    
    $ typeset -p a                             # to reproduce the the entire array creation statement
    typeset -a a=( 1 '' '' '' '' '' .... 1)    # this actually printed out 2x 1's and 999998x empty strings ('') !!!!
    

    So, it appears that a[1000000]=1 actually populates the array with 10000000 values.

    The fact your ${a[@]} doesn't produce a LOT of 'empty' lines may have something to do with your terminal (settings) ...?

    NOTE: Trying to run a[100000000]=1 blew out the memory in my (smallish) VM due to trying to create an array with 100 million entries! :-)


    I'm thinking that for sparse arrays (in zsh) you may need to look at using an associative array, eg:

    $ typeset -A c                    # designate 'c' as an associative array
    
    $ c[1]=1
    $ c[1000]=2
    
    $ typeset -p c                    # display command to rebuild 'c' associative array from scratch
    typeset -A c=( [1]=1 [100]=2 )
    
    $ echo "${#c[@]}"
    2
    $ echo "${c[@]}"
    1 2
    

    And getting list a list of indexes (aka 'keys'), values or index(key)+value pairs:

    $ echo "${(k)c[@]}"                   # list of 'k'eys
    1 1000
    
    $ echo "${(v)c[@]}"                   # list of 'v'alues
    1 2
    
    $ echo "${(kv)c[@]}"                  # list of 'k'ey + 'v'alue pairs
    1 1 1000 2