2015-09-22 7 views
9

Considerare il seguente vettore pre-ordinato x.Inversione dell'ordine delle sezioni duplicate in un vettore

x <- c(1, 2, 2, 2, 3, 5, 7, 7, 7, 8) 

order() ci mostra l'ordine del vettore.

(o <- order(x)) 
# [1] 1 2 3 4 5 6 7 8 9 10 

Ora supponiamo che io voglio invertire l'ordine dei soli duplicati/valori ripetuti di x, nel senso che voglio per invertire solo i 2 3 4 e 7 8 9 sezioni di o perché quelli sono i valori ripetuti in x. Poi, il risultato desiderato sarebbe

[1] 1 4 3 2 5 6 9 8 7 10 

Qual è il modo migliore per farlo? In questo momento ho il seguente

w <- which(duplicated(x) | duplicated(x, fromLast = TRUE)) 
o[w] <- rev(o[w]) 

Ma questo non dà la risposta corretta qui.

o 
# [1] 1 9 8 7 5 6 4 3 2 10 

PS: lo sto utilizzando per invertire l'ordine di colonne di nomi di colonne duplicate.

+0

è il vettore 'x' presume essere sempre ordinato di cominciare con o possa avere una soluzione di generalizzare per non ordinate' x's? Ad esempio, qual è il risultato desiderato per 'x <- c (1,3,5,2,7,2,7,2,7,8)'? – aashanand

+0

round di golf chiunque? 'rev (order (-x))' – rawr

risposta

15

Utilizzando data.table v1.9.6:

require(data.table) 
as.data.table(x)[, .(id = rev(.I)), by=x] 
#  x id 
# 1: 1 1 
# 2: 2 4 
# 3: 2 3 
# 4: 2 2 
# 5: 3 5 
# 6: 5 6 
# 7: 7 9 
# 8: 7 8 
# 9: 7 7 
# 10: 8 10 

In alternativa, si può fare:

order(x + sort(runif(length(x)), dec=TRUE)) 
# [1] 1 4 3 2 5 6 9 8 7 10 

(non del tutto sicuro se ci sono casi in cui questo potrebbe rompere)

+3

Come mai ti è venuta in mente quella 'runif()'? È impressionante. –

+1

L'eseguibile 'runif()' è un trucco rapido e sporco davvero impressionante. – aashanand

+1

Il file 'runif' funzionerà se si dispone di un vettore a valori interi (come fa Richard nel problema), ma suppongo che potrebbe distorcere il vettore se gli spazi tra gli elementi fossero inferiori a 1. – josliber

12

Una base R 1-liner utilizzarebbe ave per raggruppare l'ordine in base a valori univoci nella riginal vettore, applicando rev per invertire l'ordinamento per ogni gruppo:

ave(order(x), x, FUN=rev) 
# [1] 1 4 3 2 5 6 9 8 7 10 
+1

Molto bello vedere ave() usato come apply(). – aashanand