R'deki “=” ve “<-” atama operatörleri arasındaki farklar nelerdir?


713

Atama operatörleri =ile <-R arasındaki farklar nelerdir ?

Bu örneğin gösterdiği gibi operatörlerin biraz farklı olduğunu biliyorum

x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"

Ama tek fark bu mu?


45
Belirtildiği gibi burada kökeni <-sembolü aslında tek vardı eski APL klavyeler geliyor <-onlara anahtarı.
joran

Yanıtlar:


97

Atama operatörleri =ile <-R arasındaki farklar nelerdir ?

Örneğinizin gösterdiği =ve <-biraz farklı operatör önceliğine sahip olma (aynı ifadede karıştırıldıklarında değerlendirme sırasını belirler). Aslında, ?SyntaxR'de en yüksekten en alta aşağıdaki operatör öncelik tablosunu verir:

-> ->>’           rightwards assignment<- <<-’           assignment (right to left)=’                assignment (right to left)

Ama tek fark bu mu?

Atama operatörlerini sorduğunuz için : evet, tek fark bu. Ancak, başka türlü inandığınız için affedilirsiniz. Daha ?assignOpsfazla farklılık olduğu iddialarının R belgeleri bile :

Operatör <-her yerde kullanılabilirken operatöre =yalnızca en üst düzeyde (örn. Komut istemine yazılan tam ifadede) veya hazır ifadeler listesindeki alt ifadelerden biri olarak izin verilir.

Üzerine çok ince bir nokta koymayalım : R belgeleri (ince) yanlıştır [ 1 ] . Bunu göstermek kolaydır: sadece =(a) en üst seviyede olmayan (b) ifadelerin hazır ifadeler listesinde (yani {…; …}) bir alt ifade olmayan operatörün bir karşı örneğini bulmamız gerekir . - Daha fazla uzatmadan:

x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1

Açıkçası =(a) ve (b) bağlamlarının dışında bir ödev gerçekleştirdik . Öyleyse, neden temel R dili özelliğinin belgeleri on yıllardır yanlış?

Çünkü R'nin sözdiziminde sembolün =rutin olarak sınırlanan iki farklı anlamı vardır:

  1. İlk anlamı bir atama operatörü olarak . Şimdiye kadar bahsettiğimiz tek şey bu.
  2. İkinci anlamı bir operatör değil, bir değil belirteç sözdizimi o sinyalleri geçen argüman adında bir işlev çağrısında. =Operatörün aksine, çalışma zamanında hiçbir eylem gerçekleştirmez, yalnızca bir ifadenin ayrıştırma şeklini değiştirir.

Bakalım.

Genel formdaki herhangi bir kodda…

‹function_name›(‹argname› = ‹value›,)
‹function_name›(‹args›, ‹argname› = ‹value›,)

=İsimlendirilmiş argüman geçişini tanımlayan belirteç: atama operatörü değildir . Ayrıca, bazı sözdizimsel bağlamlarda =tamamen yasaktır :

if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …

Bunlardan herhangi biri ‹bla› 'de “beklenmedik' = 'hatası verecektir.

Başka bir bağlamda, =atama operatörü çağrısına karşılık gelir. Özellikle, yalnızca alt ifadenin etrafına parantez koymak, yukarıdaki (a) ve (b) 'den herhangi birini bir ödeve dönüştürür . Örneğin, aşağıdakiler atamayı gerçekleştirir:

median((x = 1 : 10))

Ayrıca:

if (! (nf = length(from))) return()

Şimdi böyle bir kodun iğrenç olduğuna itiraz edebilirsiniz (ve haklı olabilirsiniz). Ama bu kodu aldı base::file.copy(yerine fonksiyonu <-ile =çekirdek R kod temeli çok yaygın bir model olduğunu -).

John Chambers tarafından orijinal açıklama R belgelerine muhtemelen dayanmaktadır, aslında doğru açıklıyor:

[ =atamaya] dilbilgisinde yalnızca iki yerde izin verilir: en üst düzeyde (tam bir program veya kullanıcı tarafından yazılan ifade olarak); ve çevreleyen mantıksal yapıdan, parantez veya ekstra bir parantez çifti ile izole edildiğinde.


Bir itiraf: Daha önce yalan söyledim. Orada olan arasında bir ilave fark =ve <-operatörler: bunlar ayrı işlevleri çağırmak. Varsayılan olarak bu işlevler aynı şeyi yapar, ancak davranışı değiştirmek için bunlardan birini ayrı ayrı geçersiz kılabilirsiniz. Aksine <-ve ->(soldan sağa atama), sözdizimsel olarak farklı olsa da, her zaman aynı işlevi çağırın . Birini geçersiz kılmak diğerini de geçersiz kılar. Bunu bilerek nadiren pratiktir ama olabilir bazı eğlenceli Oyun oynamak için kullanılabilir .


1
R'nin belgesindeki öncelik ve hatalar hakkında, önceliği ?aslında arasında doğrudur =ve <-geçersiz kılma sırasında önemli sonuçlar doğurur ? ve neredeyse hiçbiri yoktur.
Moody_Mudskipper

@Moody_Mudskipper bu garip! Doğru gibi görünüyor, ancak uygun kaynak kodu ( main/gram.y), öncelik ?doğru belgelenmiş ve her ikisi de daha düşüktür edilir =ve <-.
Konrad Rudolph

C konuşmuyorum ama sanırım =ayrıştırma ağacı inşa edilmeden önce özel bir muamele görüyorum . Belki de işlev argümanları ile ilgili olarak , ifadenin geri kalanını ayrıştırmadan önce foo(x = a ? b)arayacağımız mantıklıdır =.
Moody_Mudskipper

@Moody_Mudskipper R-
Konrad Rudolph

2
@Moody_Mudskipper FWIW bu nihayet 4.0.0'da düzeltildi.
Konrad Rudolph

661

İşlev çağrısında bağımsız değişken değeri ayarlamak için kullandığınızda atama işleçlerindeki fark daha açıktır. Örneğin:

median(x = 1:10)
x   
## Error: object 'x' not found

Bu durumda, xişlev kapsamında bildirilir, bu nedenle kullanıcı çalışma alanında bulunmaz.

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

Bu durumda, xkullanıcı çalışma alanında bildirilir, böylece işlev çağrısı tamamlandıktan sonra kullanabilirsiniz.


R topluluğu arasında, <-S-Plus'ın (çok) eski sürümleriyle uyumluluk için atama için (işlev imzaları dışında) genel bir tercih vardır . Alanların aşağıdaki gibi durumların netleştirilmesine yardımcı olduğunu unutmayın:

x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3

Çoğu R IDE'nin yazmayı <-kolaylaştırmak için klavye kısayolları vardır . Ctrl+ =Architect'de, Alt+ -RStudio içinde ( Option+ -MacOS altında), Shift+ -emacs + ESS (alt çizgi).


Yazmakta tercih ederseniz =için <-ancak (örneğin, CRAN üzerine) herkese açık olarak yayınlandığı kodu için daha yaygın atama sembolü kullanmak istiyorum, o zaman birini kullanabilirsiniz tidy_*işlevler formatRotomatik yerine paketiyle =birlikte <-.

library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5

"Neden x <- y = 5bir hata atıyor ama vermiyor x <- y <- 5?" "Ayrıştırıcıda bulunan büyüye bağlıdır". R'nin sözdizimi şu ya da bu şekilde çözülmesi gereken birçok belirsiz durum içeriyor . Ayrıştırıcı seçer bağlı olarak farklı sıralarda ifade bit çözmek için =ya da <-kullanılmıştır.

Ne olduğunu anlamak için atamanın sessizce atanan değeri döndürdüğünü bilmeniz gerekir. Örneğin bunu açıkça yazdırarak daha net görebilirsiniz print(x <- 2 + 3).

İkinci olarak, atama için önek gösterimini kullanırsak daha açık olur. Yani

x <- 5
`<-`(x, 5)  #same thing

y = 5
`=`(y, 5)   #also the same thing

Ayrıştırıcı x <- y <- 5,

`<-`(x, `<-`(y, 5))

Bunun x <- y = 5o zaman

`<-`(x, `=`(y, 5))

ama aslında şu şekilde yorumlanır

`=`(`<-`(x, y), 5)

Bunun nedeni =, yardım sayfasında <-gösterildiği gibi önceliğin daha düşük olmasıdır ?Syntax.


4
Bu ayrıca Patrick Burns tarafından R Inferno bölüm 8.2.26'da da belirtilmiştir (Ben değil ama yine de bir öneri)
Uwe

3
Ancak, median((x = 1:10))aynı etkiye sahiptir median(x <- 1:10).
Francesco Napolitano

2
i gerçekten onları kısayollar düşünmüyorum, her durumda aynı sayıda tuşa basın
yosemite_k

5
Az önce nasıl x <- x = 5yorumlandığına dair açıklamanızın biraz yanlış olduğunu fark ettim : Gerçekte, R bunu ​`<-<-`(x, y = 5, value = 5)(kendisi aşağı yukarı eşdeğer tmp <- x; x <- `<-<-`(tmp, y = 5, value = 5)) olarak yorumlar. Olmadı!
Konrad Rudolph

4
… Ve bu cevabın ilk kısmının yanlış olduğunu ve ne yazık ki oldukça yanıltıcı olduğunu fark ettim, çünkü ortak bir yanlış anlama sürdürüyor: =Bir işlev çağrısında kullanma şekliniz atama gerçekleştirmiyor ve bir atama operatörü değil. Aynı karakteri kullanan tamamen farklı bir çözümlü R ifadesidir. Ayrıca, gösterdiğiniz kod xfonksiyon kapsamında “beyan etmez” . Fonksiyon bildirimi gerçekleştirir beyan etti. İşlev çağrısı (adlandırılmış ...argümanlarla biraz daha karmaşık hale gelir ).
Konrad Rudolph

103

Google'ın R stil kılavuzu, atama için "=" işaretini yasaklayarak sorunu basitleştirir. Kötü bir seçim değil.

https://google.github.io/styleguide/Rguide.xml

R el kitabı 5 atama operatörünün hepsinde güzel ayrıntılara girer.

http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html


133
Yanlışlıkla yapılan görevlendirmenin x<-yne zaman x < -ykastedildiği dezavantajı, beni kişisel olarak tercih ettiğim kadar rahatsız ediyor =. Kodunuzun boşluğun mevcut olmasına bağlı olması bana iyi gelmiyor. Stil önerisi olarak boşluk bırakmayı önermeniz uygun, ancak kodunuzda bir boşluk olup olmadığı farklı çalışıyor mu? Kodunuzu yeniden biçimlendirirseniz veya arama ve değiştirme özelliğini kullanırsanız, boşluk bazen kaybolabilir ve kod ters gider. Bu bir sorun değil =. IIUC, yasaklamak =" <- " gerekliliğine eşittir ; yani, yalnızca " <-" değil, boşluk içeren 3 karakter .
Matt Dowle

12
Herhangi bir 0 olmayanın TRUER tarafından değerlendirildiğini unutmayın. Bu nedenle, eğer xdaha küçük olup olmadığını test etmek istiyorsanız , uyarmayacak veya hata vermeyecek şekilde -yyazabilirsiniz if (x<-y)ve iyi çalışıyor gibi görünebilir. Ancak sadece FALSEne zaman olacak y=0.
Matt Dowle

4
Yasaklar =ve kullanırsanız <- , ekstra bir adımın grep "[^<]<-[^ ]" *.Rgerekli olmadığını iddia etmek zor . =böyle bir ihtiyacı yok grep.
Matt Dowle

34
<-Kullanabiliyorsan neden gözlerini ve parmağını incitiyorsun =? % 99,99 oranında =iyi. Bazen <<-farklı bir tarihe ihtiyaç vardır .
Fernando

10
<- 'ye odaklanma belki de + = ve - = eksikliğinin topal nedenlerinden biridir.
Chris

37

x = y = 5eşittir x = (y = 5), çünkü atama işleçleri "grup" sağdan sola, çalışır. Anlamı: 5 ysayısını, 5 sayısını bırakarak; ve sonra 5'i atayın x.

Bu aynı değildir (x = y) = 5, ki bu işe yaramaz! Anlamı: değerini atamak yiçin xdeğerini bırakarak y; ve sonra 5'i atayım, umm ..., tam olarak ne?

Farklı türde atama işleçlerini karıştırdığınızda, <-daha sıkı bağlanır =. Yani x = y <- 5, x = (y <- 5)mantıklı olan durum olarak yorumlanır .

Maalesef x <- y = 5olarak yorumlanır (x <- y) = 5çalışmıyor durumda olan!

Bkz ?Syntaxve ?assignOpsönceliği için (bağlama) ve kuralları gruplama.


Evet, Konrad Rudolph'un cevabının söylediği <- <<-gibi = öncelik tablosunda yukarıda olduğu anlamına gelir, bu da <-önce anlamlandırılacaktır. Yani, x <- y = 5olarak yürütülmelidir (x <- y) = 5.
Nick Dong

1
@Nick Dong Evet gerçekten. Yararlı bir şekilde, operatör öncelik tablosu kesin olarak ? Sözdizimi {base} içinde belgelenir .
Steve Pitchers

33

John Chambers'a göre, operatöre =yalnızca "en üst düzeyde" izin verilir if, yani aşağıdaki programlama hatasını yasadışı hale getiren gibi kontrol yapılarında izin verilmez .

> if(x = 0) 1 else x
Error: syntax error

Yazdığı gibi, "Kontrol ifadelerinde yeni atama formunun [=] kullanılmaması, eşit işleçle diğer S atamalarından daha olası programlama hatalarını (yukarıdaki örnek gibi) önler."

Bunu "çevredeki mantıksal yapıdan, diş telleri veya ekstra bir parantez çifti ile izole edilmişse" yapmayı başarabilirsiniz if ((x = 0)) 1 else x.

Bkz. Http://developer.r-project.org/equalAssign.html


11
Bu yaygın bir hata, x==0bunun yerine neredeyse her zaman kastedilmektedir.
Aaron Stack Overflow'dan ayrıldı

14
Ah, evet, "programlama hatası" dediğini göz ardı ettim. Bunun bir hataya neden olduğu iyi bir haber. Ve x=0atama olarak tercih etmek için iyi bir neden x<-0!
Steve Pitchers

7
Evet, bunun bir hataya neden olması güzel, ama ne tercih edeceğim konusunda farklı bir ders çiziyorum; =Mümkün olduğunca az kullanmayı seçtim =ve ==çok benzer görünüyorum.
Aaron Stack Overflow'dan ayrıldı

2
Bu örneğin sunuluş şekli bana çok garip geliyor. if(x = 0) 1 else xbir hata atar ve bir hatayı bulup düzeltmeme yardımcı olur. if(x <- 1) 1 else xhata atmaz ve çok kafa karıştırıcıdır.
Gregor Thomas

3
Yani, gerçekten yararlı bir hata denetleyicisi orada bir hata atar ve "her zaman elsedeğeri döndürecek işe yaramaz kodunuz var, bu şekilde yazmak mı istediniz?" Derdi, ama bu bir boru rüyası olabilir ...
TylerH

26

Operatörler <-ve =değerlendirildikleri ortama atarlar. Operatör <-her yerde kullanılabilirken operatöre =yalnızca en üst düzeyde (örn. Komut istemine yazılan tam ifadede) veya hazır ifadeler listesindeki alt ifadelerden biri olarak izin verilir .


8
"Üst düzey" ifadesinin ifade düzeyinde değil, ifade düzeyinde olduğunu düşünüyorum. Yani x <- 42tek başına bir ifade; içinde if (x <- 42) {}bir ifade olurdu ve geçerli değil. Açık olmak gerekirse, bunun küresel ortamda olup olmadığınızla ilgisi yoktur.
Steve Pitchers

1
Bu: “operatöre = sadece en üst seviyede izin verilir”, yaygın bir yanlış anlama ve tamamen yanlıştır.
Konrad Rudolph

Bu doğru değil - örneğin, ödev tam bir ifade olmamasına rağmen, bu işe yarıyor:1 + (x = 2)
Pavel Minaev

1
KonradRudolph ve PavelMinaev'in yorumlarını açıklığa kavuşturmak için, bunun tamamen yanlış olduğunu söylemek çok güçlü olduğunu düşünüyorum, ancak "çevreleyen mantıksal yapıdan, parantez veya ekstra bir parantez çifti ile izole edildiğinde" bir istisna var.
Aaron Stack Overflow'dan ayrıldı

Veya içinde function() x = 1, repeat x = 1, if (TRUE) x = 1....
Moody_Mudskipper

6

Bu aynı zamanda bu iki operatör arasındaki farkın anlaşılmasına katkıda bulunabilir:

df <- data.frame(
      a = rnorm(10),
      b <- rnorm(10)
)

İlk eleman için R atanmış değerler ve uygun isim verirken, ikinci elemanın adı biraz garip görünüyor.

str(df)
# 'data.frame': 10 obs. of  2 variables:
#  $ a             : num  0.6393 1.125 -1.2514 0.0729 -1.3292 ...
#  $ b....rnorm.10.: num  0.2485 0.0391 -1.6532 -0.3366 1.1951 ...

R sürüm 3.3.2 (2016-10-31); macOS Sierra 10.12.1


6
bunun neden olduğunu / burada neler olduğunu daha ayrıntılı açıklayabilir misiniz? (ipucu: data.framesağlanan değişkenin adını veri çerçevesindeki öğenin adı olarak kullanmaya çalışır)
Ben Bolker

Sadece düşündüm, bu muhtemelen bir hata olabilir mi? Ve eğer öyleyse, nasıl ve nerede rapor edebilirim?
Denis Rasulev

7
bu bir hata değil. Yukarıdaki yorumumdaki cevaba ipucu vermeye çalıştım. Öğenin adını ayarlarken, R öğesinin eşdeğerini kullanır make.names("b <- rnorm(10)").
Ben Bolker
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.