3

Given two columns (perhaps from a data frame) of equal length N, how can I produce a column of length 2N with the odd entries from the first column and the even entries from the second column?

Suppose I have the following data frame

df.1 <- data.frame(X = LETTERS[1:10], Y = 2*(1:10)-1, Z = 2*(1:10))

How can I produce this data frame df.2?

i <- 1
j <- 0
XX <- NA
while (i <= 10){
XX[i+j] <- LETTERS[i]
XX[i+j+1]<- LETTERS[i]
i <- i+1
j <- i-1
}

df.2 <- data.frame(X.X = XX, Y.Z = c(1:20))
Hugh
  • 15,521
  • 12
  • 57
  • 100
  • 1
    [**Here's another way**](http://stackoverflow.com/a/16443987/559784) you may be interested. – Arun Jul 13 '13 at 05:26
  • you can extend it to multiple vectors by having them in a list and doing: `unlist(ll)[order(sequence(vapply(ll, length, 0L)))]` – Arun Jul 13 '13 at 05:34

6 Answers6

5

ggplot2 has an unexported function interleave which does this.

Whilst unexported it does have a help page (?ggplot2:::interleave)

with(df.1, ggplot2:::interleave(Y,Z))
## [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
mnel
  • 113,303
  • 27
  • 265
  • 254
  • Interesting. I wrote my own interleave, not realizing there's already one sitting in a widely-used package. – Glen_b Apr 23 '13 at 02:20
  • This is a fantastic solution. Easily extensible to multiple vectors too! – Hugh Apr 23 '13 at 12:46
2

If I understand you right, you want to create a new vector twice the length of the vectors X, Y and Z in your data frame and then want all the elements of X to occupy the odd indices of this new vector and all the elements of Y the even indices. If so, then the code below should do the trick:

foo<-vector(length=2*nrow(df.1), mode='character')

foo[seq(from = 1, to = 2*length(df.1$X), by=2)]<-as.character(df.1$X)
foo[seq(from = 2, to = 2*length(df.1$X), by=2)]<-df.1$Y

Note, I first create an empty vector foo of length 20, then fill it in with elements of df.1$X and df.1$Y.

Cheers,

Danny

Arhopala
  • 376
  • 1
  • 7
  • This is a narrow second to the `ggplot2:::interleave()` solution. Yours seems safer but just a bit longer! – Hugh Apr 23 '13 at 12:45
1

You can use melt from reshape2:

library(reshape2)
foo <- melt(df.1, id.vars='X')

> foo
   X variable value
1  A        Y     1
2  B        Y     3
3  C        Y     5
4  D        Y     7
5  E        Y     9
6  F        Y    11
7  G        Y    13
8  H        Y    15
9  I        Y    17
10 J        Y    19
11 A        Z     2
12 B        Z     4
13 C        Z     6
14 D        Z     8
15 E        Z    10
16 F        Z    12
17 G        Z    14
18 H        Z    16
19 I        Z    18
20 J        Z    20

Then you can sort and pick the columns you want:

foo[order(foo$X), c('X', 'value')]
Justin
  • 42,475
  • 9
  • 93
  • 111
  • Good solution for my example but it may be the case that ordering `X` gives the wrong result. – Hugh Apr 23 '13 at 12:47
1

Another solution using base R.

First index the character vector of the data.frame using the vector [1,1,2,2 ... 10,10] and store as X.X. Next, rbind the data.frame vectors Y & Z effectively "zipping" them and store in Y.X.

> res <- data.frame(
+   X.X = df.1$X[c(rbind(1:10, 1:10))],
+   Y.Z = c(rbind(df.1$Y, df.1$Z))
+ )
> head(res)
  X.X Y.Z
1   A   1
2   A   2
3   B   3
4   B   4
5   C   5
6   C   6
Zelazny7
  • 39,946
  • 18
  • 70
  • 84
1

A one two liner in base R:

test <- data.frame(X.X=df.1$X,Y.Z=unlist(df.1[c("Y","Z")]))
test[order(test$X.X),]
thelatemail
  • 91,185
  • 12
  • 128
  • 188
0

Assuming that you want what you asked for in the first paragraph, and the rest of what you posted is your attempt at solving it.

a=df.1[df.1$Y%%2>0,1:2]
b=df.1[df.1$Z%%2==0,c(1,3)]
names(a)=c("X.X","Y.Z")
names(b)=names(a)
df.2=rbind(a, b)

If you want to group them by X.X as shown in your example, you can do:

library(plyr)
arrange(df.2, X.X)
c.gutierrez
  • 4,740
  • 1
  • 20
  • 14
  • Yes, sorry my example is misleading. It's meant to be a specific instance of the general problem and the corresponding solution. For illustrative purposes. – Hugh Apr 23 '13 at 12:35
  • Got it. Judging by what you selected as your response, you were also just looking for the odd- vs. even-index split. I interpreted your question as looking for the odd- vs. even-VALUE split .... – c.gutierrez Apr 23 '13 at 15:06