# Querying a numeric series

    library(discretes)

Once you have a numeric series, you can materialize it as a numeric vector, check which values are in it, count values in a range, and query limit points (sinks). This vignette covers these query functions.

## Materializing values from a series

Materializing a series means producing its discrete values as an ordinary numeric vector. There are three ways to do it.

### Traversing: `next_discrete()` and `prev_discrete()`

`next_discrete()` returns the next `n` discrete values in the series starting from a reference point; `prev_discrete()` does the same in the opposite direction. They return a numeric vector of values (of length at most `n`).

    x <- integers()
    next_discrete(x, from = 10)
    #> [1] 11
    next_discrete(x, from = 10, n = 5, include_from = TRUE)
    #> [1] 10 11 12 13 14
    prev_discrete(x, from = 1.3, n = 5)
    #> [1]  1  0 -1 -2 -3

When `x` is a modified series, traversal is delegated to the underlying series, and the result is mapped back.

### Pulling values: `get_discretes_at()` and `get_discretes_in()`

Rather than traversing from a reference point, you can ask for values in a range or at specific values.

`get_discretes_at()` — Gets specified discrete values from the series, if they can be found in the series (within `tol` of the base series).

    get_discretes_at(integers(), values = c(-10, 4, 3.5, 10, NA))
    #> [1] -10   4  10  NA
    get_discretes_at(integers(), values = 5.5)
    #> integer(0)

`get_discretes_in()` — Gets all discrete values within a range. The result is ordered from smallest to largest. If there are infinitely many discrete values in the range, `get_discretes_in()` throws an error; use `num_discretes()` first to check.

    get_discretes_in(integers(), from = 6.6, to = 10.1)
    #> [1]  7  8  9 10
    get_discretes_in(1 / integers(0, 5))
    #> [1] 0.2000000 0.2500000 0.3333333 0.5000000 1.0000000       Inf

### Subsetting by position: `[`

When a series has a well-defined first element (e.g. `natural1()`), you can subset by position with `[`.

    natural1()[2]
    #> [1] 2
    natural1()[c(1, 3, 5)]
    #> [1] 1 3 5

Unlike `dsct_keep()` and `dsct_drop()`, which return a new series, `[` materializes the series as a numeric vector.

The behaviour of subsetting is delegated to that of numeric vectors, so you can expect similar behaviour:

    x <- as_discretes(1:4)
    x[-1]
    #> [1] 2 3 4
    x[c(0, NA, 1, 4, 1, 5)]
    #> [1] NA  1  4  1 NA
    x[]
    #> [1] 1 2 3 4

However, not some functionality available with numeric vectors is not supported for numeric series:

- Assignment via `[`, like `x[1:3] <- ...`
- Subsetting by name, like `x["foo"]`
- Subsetting by logical vector, like `x[x < 3]` (futher, comparisons like `x < 3` or `x == 3` do not result in a supported structure).

## Counting: `num_discretes()`

`num_discretes()` returns how many discrete values lie in a range. It returns `Inf` for infinite-length series.

    num_discretes(integers(), from = -2, to = 5)
    #> [1] 8
    num_discretes(1 / 2^integers(), from = 0, to = 1)
    #> [1] Inf

## Which values are in the series?

Use `has_discretes()` to check whether given values are in the series. It returns a logical vector, one per queried value.

    has_discretes(natural1(), c(0, 1, 2, 2.5))
    #> [1] FALSE  TRUE  TRUE FALSE
    has_discretes(integers(), c(-10, 0, 10, NA))
    #> [1] TRUE TRUE TRUE   NA

`NA` in the queried values yields `NA` in the result.

## Querying sinks

A sink is a limit point of a numeric series: discrete values get arbitrarily close to it, and there are infinitely many discrete values near the sink.

`sinks()` lists all sinks in a matrix of locations and directions: approached from the left (-1) or right (+1).

    sinks(integers())
    #>      location direction
    #> [1,]      Inf        -1
    #> [2,]     -Inf         1
    sinks(0.5^natural0())
    #>      location direction
    #> [1,]        0         1
    reciprocals <- 1 / integers()
    sinks(reciprocals)
    #>      location direction
    #> [1,]        0         1
    #> [2,]        0        -1

`has_sink_in()` or `has_sink_at()` are convenience functions that test for a sink in an interval or at a value.

    has_sink_in(integers())
    #> [1] TRUE
    has_sink_at(integers(), Inf)
    #> [1] TRUE
    has_sink_at(integers(), -Inf, dir = "right")
    #> [1] TRUE

For `has_sink_at()`, `dir` can be `"either"` (any direction), `"left"` or `"right"` (sink approached from that side), or `"both"` (approached from both sides). When a series has a sink, there is no “next” or “previous” discrete value on the far side of the sink (e.g. `next_discrete(reciprocals, from = -1)` returns nothing).