2016-06-08 12 views
15

Ho difficoltà a capire perché == e %in% produrrebbero risultati diversi se applicati a vettori di caratteri che dipendono, a quanto pare, solo dalla codifica dei vettori. Un esempio:== e% in% differiscono in base alla codifica dei caratteri?

a <- 'Köln' 
Encoding(a) <- 'unknown' 
Encoding(a) 
# [1] "unknown" 

b <- a 
Encoding(b) <- 'UTF-8' 

a == b 
# [1] TRUE 
a %in% b 
# [1] FALSE 

Aggiornamento:

sembra che il risultato è anche dipendente dalla piattaforma. Le due istruzioni di ritorno:

  • TRUE e FALSE su R 3.3.0 su OS X 10.11.5
  • FALSE e FALSE su R 3.3.0 su Windows 10 (64 bit)
  • TRUE e TRUE su R 3.2.3 su CentOS 7

Sto iniziando a pensare che questo sia un bug.

+1

'una% in% c (a, b)' 'è vero Encoding' -?' Match, pmatch, charmatch, duplicato e unico tutti i match in UTF-8 se uno qualsiasi degli elementi sono contrassegnati come UTF-8.' – rawr

+0

E la documentazione di '==' dice che i caratteri sono tutti convertiti in UTF-8 prima del confronto ... Sarei curioso del perché il diverso comportamento però. – joran

+1

@rawr Beh, sì, ma 'a' è in' c (a) 'quindi è anche in' c (a, b) '. Ma perché non è 'b' in' c (a) '? '% in%' non controlla che il nome della variabile sia identico, solo valori e non capisco perché i valori non siano identici dato che '==' restituisce 'TRUE'. – RoyalTS

risposta

3

Si tratta in effetti di un bug ed era fixed in 3.3.1.

Il comportamento è in realtà un po 'più strano che il vostro esempio indica, in che si ottiene solo FALSE quando si dispone di un elemento sul lato sinistro della %in%:

> a %in% b 
[1] FALSE 
> c(a, a) %in% b 
[1] TRUE TRUE 

Come implicita dai commenti, %in% solo chiamate match, in modo che il problema può essere visto anche lì:

> match(a, b) 
[1] NA 
> match(c(a, a), b) 
[1] 1 1 

Gli argomenti importanti da %in% e match sono x e table, in cui una delle funzioni cerca x in table. Sotto il cofano, R lo fa nella funzione match5 definita in unique.c. Nel caso in cui si disponga di più di uno x, match5 creerà una tabella hash da table per abilitare ricerche veloci. Se si scava il codice, si vedrà che il confronto viene eseguito in una funzione denominata sequal, che restituisce Seql(STRING_ELT(x, i), STRING_ELT(y, j)) (beh, in realtà è un po 'più complesso di questo *). Poi se si va a guardare Seql in memory.c, troverete:

int result = !strcmp(translateCharUTF8(a), translateCharUTF8(b)); 

Il che, come si può vedere, converte le stringhe in UTF-8.

Tuttavia, se x ha un solo elemento, è stupido per passare attraverso la briga di creare una tabella di hash, dal momento che possiamo solo eseguire la scansione attraverso table una volta per vedere se x c'è. In 3.3.0, il codice per verificare l'uguaglianza tra x e ogni elemento di table non ha utilizzato Seql e non ha convertito la stringa in UTF-8. Ma a partire dal 3.3.1, viene utilizzato Seql, quindi il comportamento è corretto.

* Un po 'da parte sull'equità delle stringhe: R memorizzerà effettivamente le stringhe in modo che non debba memorizzare un gruppo di copie. Quindi se due stringhe si trovano nella stessa posizione, sono uguali e non è necessario controllare ulteriormente!

> .Internal(inspect("Köln")) 
@10321b758 16 STRSXP g0c1 [NAM(2)] (len=1, tl=0) 
    @106831eb8 09 CHARSXP g1c1 [MARK,gp=0x28,ATT] [UTF8] [cached] "Köln" 
> .Internal(inspect(b)) 
@106831cd8 16 STRSXP g1c1 [MARK,NAM(2)] (len=1, tl=0) 
    @106831eb8 09 CHARSXP g1c1 [MARK,gp=0x28,ATT] [UTF8] [cached] "Köln" 
Problemi correlati