در مفهوم Vectors دیدیم که یک بردار میتواند در یک عبارت شرطی استفاده شود و یک بردار منطقی بدهد.
این به نوبهی خود میتواند در توابعی مانند all() و any() استفاده شود.
v <- c(4, 7, 10)
v >= 6
#> [1] FALSE TRUE TRUE
all(v > 6)
#> [1] FALSE # not all elements match this condition
any(v > 6)
#> [1] TRUE # at least one element matches
این تکنیک بسیار قدرتمندتر از این است.
عنصرهای انتخابشدهی یک بردار را میتوان با یک شمارهی اندیس یا برداری از اندیسها بیرون کشید:
v <- 5:10
v
#> [1] 5 6 7 8 9 10
v[3]
#> [1] 7
v[c(2, 4)]
#> [1] 6 8
در روشی دیگر، از یک بردار منطقی برای فیلتر کردن بردار اصلی استفاده کنید، که زیرمجموعهای از عنصرهای متناظر با مقدار TRUE را برمیگرداند:
v <- 1:3
bools <- c(FALSE, TRUE, TRUE)
v[bools]
#> [1] 2 3
از آنجا تا تولید بردار منطقی با یک عبارت شرطی فاصلهی کمی است:
bools <- v >= 2
bools
#> [1] FALSE TRUE TRUE
v[bools]
#> [1] 2 3
# simpler form
v[v >= 2]
#> [1] 2 3
این عبارتهای شرطی میتوانند بهطور دلخواه پیچیده باشند و چندین بردار یا تابع را درگیر کنند:
v <- 1:10
w <- 10:1
# pairwise comparison
v > w
#> [1] FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
# shorter form
v[v > w]
#> [1] 6 7 8 9 10
ما این مفهوم را «فیلتر کردن بردار» نامیدیم، به این امید که برای گستردهترین طیف برنامهنویسان قابلفهم باشد.
در جامعهی R، اصطلاح «Subsetting» احتمالاً رایجتر است.
برای سادگی، همهی مثالهای بالا بردارهایی با طول یکسان را مقایسه میکردند. اگر طولها ناهماهنگ باشند چه اتفاقی میافتد؟
پاسخ چیزی است که اگر عمداً استفاده شود قدرتمند است، اما اگر ناخواسته پیش بیاید گیجکننده است.
یک مثال:
v <- 1:6
cond <- c(TRUE, FALSE)
v[cond]
#> [1] 1 3 5
چه اتفاقی افتاد؟ ما برداری با طول ۶ را با یک بردار منطقی به طول ۲ اندیسگذاری کردیم، اما در نتیجه برداری با طول ۳ به دست آوردیم.
اگر برداری بهنوعی برای عبارتی که در آن استفاده میشود «بیش از حد کوتاه» باشد، R آن را تا رسیدن به طول موردنظر تکرار میکند: به این کار «بازیافت» میگویند.
این کار بردار c(TRUE, FALSE) ما را به c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE) تبدیل کرد و سپس v[cond] مقادیر TRUE را از v برگرداند: در این مورد، اعداد فرد.
حالا در مثال بعدی چه اتفاقی میافتد؟
v <- 1:3
0.5 * v
#> [1] 0.5 1.0 1.5
2 + v
#> [1] 3 4 5
در نگاه اول شبیه ضرب اسکالر و (کمی عجیب) جمع اسکالر به نظر میرسد، اما در R اسکالر وجود ندارد.
در عوض، اعداد بازیافت میشوند تا برداری همطول با v به دست آید، سپس عمل حسابی بهصورت عنصربهعنصر با استفاده از c(0.5, 0.5, 0.5) یا c(2, 2, 2) اعمال میشود.
بازیافت بسیار بسیار مفید است، اما مطمئن شوید که منظورتان همین است.
کمی ناهماهنگی در طول بردارها (مثلاً ۹۹ در برابر ۱۰۰) میتواند Bugهای گیجکننده ایجاد کند.
بعضی از نویسندگان توصیه میکنند که بازیافت فقط وقتی استفاده شود که یکی از بردارها طول ۱ داشته باشد.
تابع which() یک آرگومان منطقی میگیرد و برداری از اندیسها را برمیگرداند که مقدار TRUE میدهند.
v
#> [1] 2 7 9
v[v > 5] # returns values
#> [1] 7 9
which(v > 5) # returns indices
#> [1] 2 3
بخشهای قبلی دربارهی یافتن عنصرهایی بود که با معیاری مطابقت دارند.
اگر فقط میخواهید بدانید که آیا بردار شامل عنصر مشخصی هست یا نه، از عملگر %in% استفاده میشود.
3 %in% 1:5
#> [1] TRUE
7 %in% 1:5
#> [1] FALSE
این از نظر عملکردی معادل کد زیر است، اما بسیار راحتتر:
length(v[v == 3]) > 0
#> [1] TRUE
عملگر %notin% هم وجود دارد که not منطقیِ %in% را میدهد.