From g@bembecker @end|ng |rom gm@||@com  Tue Oct 29 20:43:15 2019
From: g@bembecker @end|ng |rom gm@||@com (Gabriel Becker)
Date: Tue, 29 Oct 2019 12:43:15 -0700
Subject: [Rd] 
 head.matrix can return 1000s of columns -- limit to n or add
 new argument?
In-Reply-To: <CAD4oTHF_e4rtHu0S5bUu38+kQSEHXwun3Sv9-CbK+xN9tSc2hA@mail.gmail.com>
References: <CAPRVBcxsAkcgr3mDc4skTe8DTxJaYe2xyhk3QMk3odW1MGcyNA@mail.gmail.com>
 <CAB8pepxS2mRtd+522OwjixnM6ZjYxb+X0dc4vMGn6QxdFYBmVQ@mail.gmail.com>
 <CAD4oTHH=LpeEj6h6xYdOGsreS-GDCGdgJV5wpaUR3Pjuh5_M1w@mail.gmail.com>
 <CAPRVBczYZHO3JaFVfNeNNV0-YMRvX3CUYhUvLCjophDEoP+XgQ@mail.gmail.com>
 <23935.14449.965488.684663@stat.math.ethz.ch>
 <CAPRVBcwMY=GAVfFeCwowQsxP31Y=_B2ducosThN+8V91WESB8Q@mail.gmail.com>
 <20449_1568703158_x8H6qIDG009669_f8285123-371f-5d4b-1281-6cc085dba122@fredhutch.org>
 <22204_1568723392_x8HCSG3F015456_674779E0-B1F6-4DC2-9F1C-D5D48B044B66@mcmaster.ca>
 <AD725242-0FB7-4004-9F16-304E345A363A@mcmaster.ca>
 <23937.1791.389379.103733@stat.math.ethz.ch>
 <CAD4oTHF_e4rtHu0S5bUu38+kQSEHXwun3Sv9-CbK+xN9tSc2hA@mail.gmail.com>
Message-ID: <CAD4oTHFf7Zp+Xe3jvv7oirLWgZm7ZiSNWZvbrEsqJGfrL6Q2wQ@mail.gmail.com>

Hi all,

So I've started working on this and I ran into something that I didn't
know, namely that for x a multi-dimensional (2+) array, head(x) and tail(x)
ignore dimension completely, treat x as an atomic vector, and return an
(unclassed) atomic vector:

> x = array(100, c(4, 5, 5))

> dim(x)

[1] 4 5 5

> head(x, 1)

[1] 100

> class(head(x))

[1] "numeric"


(For a 1d array, it does return another 1d array).

When extending head/tail to understand multiple dimensions as discussed in
this thread, then, should the behavior for 2+d arrays be explicitly
retained, or should head and tail do the analogous thing (with a head(<2d
array>) behaving the same as head(<matrix>), which honestly is what I
expected to already be happening)?

Are people using/relying on this behavior in their code, and if so, why/for
what?

Even more generally, one way forward is to have the default methods check
for dimensions, and use length if it is null:

tail.default <- tail.data.frame <- function(x, n = 6L, ...)
{
    if(any(n == 0))
        stop("n must be non-zero or unspecified for all dimensions")
    if(!is.null(dim(x)))
        dimsx <- dim(x)
    else
        dimsx <- length(x)

    ## this returns a list of vectors of indices in each
    ## dimension, regardless of length of the the n
    ## argument
    sel <- lapply(seq_along(dimsx), function(i) {
        dxi <- dimsx[i]
        ## select all indices (full dim) if not specified
        ni <- if(length(n) >= i) n[i] else dxi
        ## handle negative ns
        ni <- if (ni < 0L) max(dxi + ni, 0L) else min(ni, dxi)
        seq.int(to = dxi, length.out = ni)
    })
    args <- c(list(x), sel, drop = FALSE)
    do.call("[", args)
}


I think this precludes the need for a separate data.frame method at all,
actually, though (I would think) tail.data.frame would still be defined and
exported for backwards compatibility. (the matrix method has some extra
bits so my current conception of it is still separate, though it might not
NEED to be).

The question then becomes, should head/tail always return something with
the same dimensionally (number of dims) it got, or should data.frame and
matrix be special cased in this regard, as they are now?

What are people's thoughts?
~G

	[[alternative HTML version deleted]]



[Rd] head.matrix can return 1000s of columns -- limit to n or add new argument?
Gabriel Becker