The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

flexseq

flexseq basics

flexseq is a persistent sequence type, with many of the same features as an R list(), including storing arbitrary items. All updates return a new object and keep the original unchanged.

x <- flexseq(1, 2, 3)
x
#> Unnamed flexseq with 3 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] 1
#> 
#> [[2]]
#> [1] 2
#> 
#> [[3]]
#> [1] 3

x2 <- as_flexseq(letters[1:5])
x2
#> Unnamed flexseq with 5 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "b"
#> 
#> ... (skipping 1 element)
#> 
#> [[4]]
#> [1] "d"
#> 
#> [[5]]
#> [1] "e"

Names and indexing

Flexseqs may be named, but if any are named they must all have unique non-NULL names. Large named flexseqs are somewhat slower than unnamed ones; for efficient key/value stores consider using an ordered_sequence().

x <- flexseq(a = 1, b = 2, c = 3)
x
#> Named flexseq with 3 elements.
#> 
#> Elements:
#> 
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
#> 
#> $c
#> [1] 3
x[c("c", "b")]
#> Named flexseq with 2 elements.
#> 
#> Elements:
#> 
#> $c
#> [1] 3
#> 
#> $b
#> [1] 2

x$b <- NULL # delete b
x
#> Named flexseq with 2 elements.
#> 
#> Elements:
#> 
#> $a
#> [1] 1
#> 
#> $c
#> [1] 3

In general indexing and slicing works as it does with lists: [] returns a sublist indexed by integer (by position), character vector (by name if named), or logical vector (by inclusion). Note that these operations are \(O(k\log n)\) where \(k\) is the length of the indexing vector.

x <- as_flexseq(letters[1:6])

x[[3]]
#> [1] "c"

x[c(1, 3, 5)]
#> Unnamed flexseq with 3 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "c"
#> 
#> [[3]]
#> [1] "e"

End operations

Flexseqs support pushing new elements onto the front or back of the sequences, peeking at the front or back (i.e., getting a copy of the first or last item), and popping from the front or back, which returns the removed element and a copy of the flexseq input with that item removed. pop_front() and pop_back() both return a list with fields $value and $remaining; peek_back() is the symmetric counterpart to peek_front().

x <- as_flexseq(4:6)

x <- x |>
  push_back(100) |>
  push_front(50)

x
#> Unnamed flexseq with 5 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] 50
#> 
#> [[2]]
#> [1] 4
#> 
#> ... (skipping 1 element)
#> 
#> [[4]]
#> [1] 6
#> 
#> [[5]]
#> [1] 100

xpopped <- pop_front(x)

xpopped$value
#> [1] 50
xpopped$remaining
#> Unnamed flexseq with 4 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] 4
#> 
#> [[2]]
#> [1] 5
#> 
#> [[3]]
#> [1] 6
#> 
#> [[4]]
#> [1] 100

Positional operations

Beyond the ends, flexseqs support arbitrary-position persistent operations. peek_at() is the non-throwing positional read (compare with [[, which errors when out of bounds); pop_at() removes an element at a given index and returns $value/$remaining; insert_at() inserts before a given index, or at length(x) + 1 to append.

x <- flexseq("a", "b", "c", "d")

peek_at(x, 10)  # NULL, no error
#> NULL

out <- pop_at(x, 2)
out$value
#> [1] "b"
out$remaining
#> Unnamed flexseq with 3 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "c"
#> 
#> [[3]]
#> [1] "d"

insert_at(x, 3, c("x", "y"))
#> Unnamed flexseq with 6 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] "a"
#> 
#> [[2]]
#> [1] "b"
#> 
#> ... (skipping 2 elements)
#> 
#> [[5]]
#> [1] "c"
#> 
#> [[6]]
#> [1] "d"

Transforming and combining

c() concatenates flexseqs, and fapply() applies a function to each element of one returning the result as a flexseq, analygous to lapply() for R lists.

x <- as_flexseq(4:6)
x2 <- as_flexseq(8:10)

c(x, x2)
#> Unnamed flexseq with 6 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] 4
#> 
#> [[2]]
#> [1] 5
#> 
#> ... (skipping 2 elements)
#> 
#> [[5]]
#> [1] 9
#> 
#> [[6]]
#> [1] 10

x <- as_flexseq(1:3)
fapply(x, function(el) el * 10)
#> Unnamed flexseq with 3 elements.
#> 
#> Elements:
#> 
#> [[1]]
#> [1] 10
#> 
#> [[2]]
#> [1] 20
#> 
#> [[3]]
#> [1] 30

merge(x, y) is provided as an alias for c(x, y) so that merge() works uniformly across the package’s four structure types. For flexseq, c() and merge() are equivalent; the distinction matters for ordered_sequence, interval_index, and priority_queue, where merge() performs a proper sorted/priority-aware combine.

loop() (re-exported from the coro package) enables for-loop traversal, yielding elements left-to-right lazily without materializing a list.

x <- flexseq("a", "b", "c", "d")

loop(for (el in x) {
  print(el)
})
#> [1] "a"
#> [1] "b"
#> [1] "c"
#> [1] "d"

For named flexseqs, loop() yields bare values (matching peek_front()); use as.list() when you need names alongside values.

x <- flexseq(a = 1, b = 2, c = 3)
loop(for (el in x) print(el))
#> [1] 1
#> [1] 2
#> [1] 3

Plain for (el in x) (without loop()) does not dispatch to the iteration protocol — it walks the underlying finger-tree storage and yields internal nodes rather than sequence elements. Always wrap with loop().

Flexseqs convert back to standard R structures with as.list() (preserves names and list semantics) and unlist() (atomic vector when possible). length() returns the element count in O(1), and str() gives a compact diagnostic display.

x <- flexseq(a = 1, b = 2, c = 3)

as.list(x)
#> $a
#> [1] 1
#> 
#> $b
#> [1] 2
#> 
#> $c
#> [1] 3
unlist(x)
#> a b c 
#> 1 2 3
length(x)
#> [1] 3

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.