2016-06-08 12 views
15

Es fällt mir schwer zu verstehen, warum == und %in% unterschiedliche Ergebnisse liefern würden, wenn sie auf Zeichenvektoren angewendet werden, die, wie es scheint, nur auf die Codierung von Vektoren abhängen. Ein Beispiel:== und% in% unterscheiden sich basierend auf Zeichencodierung?

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 

aktualisieren:

Es erscheint das Ergebnis ist auch plattformabhängig. Die beiden Anweisungen geben:

  • TRUE und FALSE auf R 3.3.0 auf OS X 10.11.5
  • FALSE und FALSE auf R 3.3.0 unter Windows 10 (64-Bit)
  • TRUE und TRUE auf R 3.2.3 auf CentOS 7

Ich fange an zu denken, dass dies ein Fehler ist.

+1

'a% in% c (a, b)' gilt 'Encoding' -' Spiel, pmatch, charmatch, vervielfältigt und einzigartige Spiel in UTF-8, wenn eine der Elemente sind markiert als UTF-8.' – rawr

+0

Und die Dokumentation für '==' sagt, dass alle Zeichen vor dem Vergleich in UTF-8 konvertiert werden ... Ich wäre neugierig, warum das unterschiedliche Verhalten obwohl. – joran

+1

@raw Nun ja, aber 'a' steht in' c (a) 'so ist es auch in' c (a, b) '. Aber warum ist 'b' nicht in' c (a) '? '% in%' überprüft nicht, ob der Variablenname identisch ist, nur Werte und ich verstehe nicht, warum die Werte nicht identisch sind, da '==' 'TRUE' zurückgibt. – RoyalTS

Antwort

3

Es ist in der Tat ein Fehler, und es war fixed in 3.3.1.

Das Verhalten ist eigentlich ein bisschen seltsamer als Ihr Beispiel zeigt, dass Sie nur FALSE erhalten, wenn Sie ein Element auf der linken Seite von %in% haben:

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

Wie die Kommentare impliziert, %in% nur Anrufe match, so kann das Problem auch dort zu sehen:

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

die wichtigen Argumente %in% und match sind x und table, wobei jede Funktion nach x in table sucht. Unter der Haube macht R dies in der match5-Funktion, die in unique.c definiert ist. Für den Fall, dass Sie mehr als eine x haben, wird match5 eine Hash-Tabelle aus table erstellen, um schnelle Suchvorgänge zu ermöglichen. Wenn Sie den Code durchforsten, werden Sie sehen, dass der Vergleich in einer Funktion namens sequal erfolgt, die Seql(STRING_ELT(x, i), STRING_ELT(y, j)) zurückgibt (nun, es ist tatsächlich ein bisschen komplexer als das *). Dann, wenn man sich Seql in memory.c suchen gehen, werden Sie finden:

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

, die, wie Sie sehen können, die Strings in UTF-8 konvertiert.

Wenn jedoch x nur ein Element hat, es ist dumm durch die Mühe zu gehen, um eine Hash-Tabelle zu erstellen, da wir nur durch table einmal scannen können, um zu sehen, ob x ist. In 3.3.0 hat der Code, der auf Gleichheit zwischen x und jedem Element von table überprüft wurde, Seql nicht verwendet und die Zeichenfolge nicht in UTF-8 konvertiert. Aber ab 3.3.1 wird Seql verwendet, also ist das Verhalten festgelegt.

* Ein wenig beiseite bei String-Gleichheit: R wird tatsächlich Strings Cache, so dass es nicht eine Reihe von Kopien speichern muss. Wenn also zwei Strings am gleichen Ort sind, sind sie gleich und es ist nicht nötig, weiter zu suchen!

> .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" 
Verwandte Themen