Skip to content

This provides a common interface to extracting and modifying observations for all vector types, regardless of dimensionality. It is an analog to [ that matches vec_size() instead of length().

Usage

vec_slice(x, i)

vec_slice(x, i) <- value

vec_assign(x, i, value, ..., x_arg = "", value_arg = "")

Arguments

x

A vector

i

An integer, character or logical vector specifying the locations or names of the observations to get/set. Specify TRUE to index all elements (as in x[]), or NULL, FALSE or integer() to index none (as in x[NULL]).

value

Replacement values. value is cast to the type of x, but only if they have a common type. See below for examples of this rule.

...

These dots are for future extensions and must be empty.

x_arg, value_arg

Argument names for x and value. These are used in error messages to inform the user about the locations of incompatible types and sizes (see stop_incompatible_type() and stop_incompatible_size()).

Value

A vector of the same type as x.

Genericity

Support for S3 objects depends on whether the object implements a vec_proxy() method.

  • When a vec_proxy() method exists, the proxy is sliced and vec_restore() is called on the result.

  • Otherwise vec_slice() falls back to the base generic [.

Note that S3 lists are treated as scalars by default, and will cause an error if they don't implement a vec_proxy() method.

Differences with base R subsetting

  • vec_slice() only slices along one dimension. For two-dimensional types, the first dimension is subsetted.

  • vec_slice() preserves attributes by default.

  • vec_slice<-() is type-stable and always returns the same type as the LHS.

Dependencies

vctrs dependencies

base dependencies

If a non-data-frame vector class doesn't have a vec_proxy() method, the vector is sliced with [ instead.

Examples

x <- sample(10)
x
#>  [1]  6  5  7  1  2  4  3 10  9  8
vec_slice(x, 1:3)
#> [1] 6 5 7

# You can assign with the infix variant:
vec_slice(x, 2) <- 100
x
#>  [1]   6 100   7   1   2   4   3  10   9   8

# Or with the regular variant that doesn't modify the original input:
y <- vec_assign(x, 3, 500)
y
#>  [1]   6 100 500   1   2   4   3  10   9   8
x
#>  [1]   6 100   7   1   2   4   3  10   9   8


# Slicing objects of higher dimension:
vec_slice(mtcars, 1:3)
#>                mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4     21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710    22.8   4  108  93 3.85 2.320 18.61  1  1    4    1

# Type stability --------------------------------------------------

# The assign variant is type stable. It always returns the same
# type as the input.
x <- 1:5
vec_slice(x, 2) <- 20.0

# `x` is still an integer vector because the RHS was cast to the
# type of the LHS:
vec_ptype(x)
#> integer(0)

# Compare to `[<-`:
x[2] <- 20.0
vec_ptype(x)
#> numeric(0)


# Note that the types must be coercible for the cast to happen.
# For instance, you can cast a double vector of whole numbers to an
# integer vector:
vec_cast(1, integer())
#> [1] 1

# But not fractional doubles:
try(vec_cast(1.5, integer()))
#> Error in eval(expr, envir, enclos) : 
#>   Can't convert `1.5` <double> to <integer>.

# For this reason you can't assign fractional values in an integer
# vector:
x <- 1:3
try(vec_slice(x, 2) <- 1.5)
#> Error in `vec_slice<-`(`*tmp*`, 2, value = 1.5) : 
#>   Can't convert `1.5` <double> to <integer>.