Skip to the content.

List

Indexed array container. Wraps a bash indexed array with object semantics. Supports push/pop, shift/unshift, random access, negative indices, and slicing.

Contents


Dependencies

. boop List    # automatically loads Container

Constructor

into=l List

Creates an empty list. Populate it with push, set, or unshift.

Methods

Element Access

into=val $l.get 0          # first element
into=val $l.get -1         # last element (Python-style negative index)
$l.set 0 "new_first"       # replace first element
$l.set -1 "new_last"       # replace last element
$l.has 0 && printf "exists\n"  # bounds check (exit code)

Out-of-range get returns empty string. Out-of-range set and delete crash.

Stack Operations (LIFO)

$l.push "alpha"             # append to end
$l.push "a" "b" "c"        # append multiple
into=val $l.pop             # remove and return last element

Queue Operations (FIFO)

$l.unshift "first"          # prepend to beginning
into=val $l.shift           # remove and return first element

shift and unshift are O(n) — they rebuild the array. For heavy queue work, consider the access pattern cost.

Slicing

into=s $l.slice 1 3         # elements at index 1, 2 (end exclusive)
into=s $l.slice 2           # index 2 through end
into=s $l.slice -2          # last two elements

Returns a newline-delimited string.

Callback Iteration

my_callback() { printf "[%s] %s\n" "$1" "$2"; }
$l.each my_callback         # calls: my_callback 0 "alpha"
                             #        my_callback 1 "beta"

If the callback returns non-zero, iteration stops immediately.

$l.contains "banana"             # exit 0 if found, 1 if not
into=pos $l.indexOf "banana"     # pos="1" (or exit 1 if not found)

Both are O(n) linear scans. contains is a thin wrapper over indexOf that discards the position and returns only the exit code.

Iterator (Stateful Cursor)

# Lazy delegation — auto-created on first use
while $l.hasNext; do
  into=val $l.next
  into=idx $l.iterIndex
  printf "[%s] %s\n" "$idx" "$val"
done
$l.iterReset                # back to start

# Explicit — independent cursor
into=iter $l.iterator
while $iter.hasNext; do
  into=val $iter.next
  printf "%s\n" "$val"
done

See Container.md for full iterator documentation, including multiple independent cursors and Map snapshot behavior.

Utility

into=n $l.length            # element count
$l.clear                    # remove all elements
$l.delete 2                 # remove element at index, re-index
$l.isEmpty && printf "empty\n"  # boolean check
$l.destroy                  # clean up companion array + registry

Serialization

into=s $l.toString          # List(_id)[ "alpha", "beta", "gamma" ]
into=s $l.toArray           # newline-delimited values

Functional Operations

filter

Return a new List containing only elements for which the callback returns 0.

is_long() { (( ${#1} > 3 )); }

into=names List
$names.push "Al" "Bob" "Charlie" "Dave" "Elizabeth"

into=long $names.filter is_long
# long is a new List: ["Charlie", "Dave", "Elizabeth"]
# $names is unchanged

Callback signature: callback value → exit 0 to keep, non-zero to discard.

On an empty list, returns a new empty List (exit 0).

map

Return a new List with each element transformed by the callback.

upcase() { _Result="${1^^}"; }

into=words List
$words.push "hello" "world"

into=shouting $words.map upcase
# shouting is a new List: ["HELLO", "WORLD"]

Callback signature: callback value → sets _Result to the transformed value.

On an empty list, returns a new empty List (exit 0).

reduce

Collapse the list to a single scalar by applying a combining callback across all elements. The first element is the starting value; the callback begins combining from the second element onward.

add() { _Result=$(( $1 + $2 )); }

into=nums List
$nums.push 10 20 30 40

into=total $nums.reduce add    # total="100"

Callback signature: callback running_total current_value → sets _Result to the new running total.

On an empty list: returns empty string, exit code 1. On a single-element list: returns that element directly (callback not called).

do (pipeline)

Apply a sequence of operations in one call. Intermediates are created and destroyed automatically — the caller only sees the final result.

is_even() { (( $1 % 2 == 0 )); }
double_it() { _Result=$(( $1 * 2 )); }
add() { _Result=$(( $1 + $2 )); }

into=nums List
$nums.push 5 10 15 20 25 30 35 40 45

into=result $nums.do filter:is_even map:double_it reduce:add
# result="200"

Operations are op:callback pairs. Recognized ops: filter, map, reduce.

Syntax is flexible — all of these are equivalent:

$list.do "filter:is_even,map:double_it,reduce:add"
$list.do "filter:is_even, map:double_it, reduce:add"
$list.do filter:is_even map:double_it reduce:add
$list.do "filter : is_even" "map : double_it" "reduce : add"

Commas, spaces around colons, and multiple arguments are all accepted. The original list is never modified or destroyed.

Composition

List elements can be any string, including object IDs:

into=inner List
$inner.push "a" "b"

into=outer List
$outer.push "$inner"        # nested list

into=val $outer.itemAt 0 1  # "b" — traverses into inner list

Example

. boop List

into=l List
$l.push "hello" "world" "foo"
into=v $l.get 0
printf "%s\n" "$v"              # hello

into=v $l.pop
printf "%s\n" "$v"              # foo

into=n $l.length
printf "%s\n" "$n"              # 2

# Walk with each
show() { printf "  [%s] %s\n" "$1" "$2"; }
$l.each show
#   [0] hello
#   [1] world

# Walk with iterator
while $l.hasNext; do
  into=val $l.next
  printf "-> %s\n" "$val"
done
# -> hello
# -> world