Tóm tắt: Nhiều ngôn ngữ lập trình đương đại (hầu hết?) Được sử dụng rộng rãi có ít nhất một số ADT [kiểu dữ liệu trừu tượng] nói chung, đặc biệt,
chuỗi (một chuỗi bao gồm các ký tự)
danh sách (một bộ sưu tập các giá trị) và
loại dựa trên bản đồ (một mảng không có thứ tự ánh xạ các khóa thành các giá trị)
Trong ngôn ngữ lập trình R, hai ngôn ngữ đầu tiên được triển khai lần lượt là character
và vector
.
Khi tôi bắt đầu học R, có hai điều rõ ràng ngay từ đầu: list
là kiểu dữ liệu quan trọng nhất trong R (vì đó là lớp cha mẹ của R data.frame
), và thứ hai, tôi chỉ không thể hiểu cách chúng hoạt động, ít nhất là không đủ tốt để sử dụng chúng một cách chính xác trong mã của tôi.
Đối với một điều, dường như đối với tôi, list
kiểu dữ liệu của R là cách triển khai ADT bản đồ đơn giản ( dictionary
trong Python, NSMutableDictionary
trong Objective C, hash
trong Perl và Ruby, object literal
trong Javascript, v.v.).
Chẳng hạn, bạn tạo chúng giống như bạn làm từ điển Python, bằng cách chuyển các cặp khóa-giá trị cho hàm tạo (mà trong Python thì dict
không list
):
x = list("ev1"=10, "ev2"=15, "rv"="Group 1")
Và bạn truy cập vào các mục của Danh sách R giống như các mục trong từ điển Python, vd x['ev1']
. Tương tự, bạn có thể truy xuất chỉ 'khóa' hoặc chỉ 'giá trị' bằng cách:
names(x) # fetch just the 'keys' of an R list
# [1] "ev1" "ev2" "rv"
unlist(x) # fetch just the 'values' of an R list
# ev1 ev2 rv
# "10" "15" "Group 1"
x = list("a"=6, "b"=9, "c"=3)
sum(unlist(x))
# [1] 18
nhưng R list
cũng không giống như các ADT loại bản đồ khác (trong số các ngôn ngữ tôi đã học bằng mọi cách). Tôi đoán rằng đây là hệ quả của thông số ban đầu cho S, tức là ý định thiết kế DSL dữ liệu / thống kê [ngôn ngữ dành riêng cho tên miền] từ đầu.
ba sự khác biệt đáng kể giữa R list
s và các loại ánh xạ trong các ngôn ngữ khác được sử dụng rộng rãi (ví dụ: Python, Perl, JavaScript):
đầu tiên , list
s trong R là một tập hợp có thứ tự , giống như các vectơ, mặc dù các giá trị được khóa (nghĩa là các khóa có thể là bất kỳ giá trị có thể băm nào, không chỉ là số nguyên tuần tự). Gần như luôn luôn, kiểu dữ liệu ánh xạ trong các ngôn ngữ khác là không có thứ tự .
thứ hai , list
s có thể được trả về từ các hàm ngay cả khi bạn chưa bao giờ chuyển vào list
khi bạn gọi hàm và mặc dù hàm trả về list
không chứa hàm tạo (rõ ràng) list
(Tất nhiên, bạn có thể xử lý vấn đề này trong thực tế bằng cách gói kết quả trả về trong một cuộc gọi đến unlist
):
x = strsplit(LETTERS[1:10], "") # passing in an object of type 'character'
class(x) # returns 'list', not a vector of length 2
# [1] list
Một tính năng đặc biệt thứ ba của R list
: dường như họ không thể là thành viên của một ADT khác, và nếu bạn cố gắng làm điều đó thì container chính bị ép buộc a list
. Ví dụ,
x = c(0.5, 0.8, 0.23, list(0.5, 0.2, 0.9), recursive=TRUE)
class(x)
# [1] list
ý định của tôi ở đây không phải là chỉ trích ngôn ngữ hay cách nó được ghi chép lại; tương tự, tôi không cho rằng có bất cứ điều gì sai với list
cấu trúc dữ liệu hoặc cách nó hoạt động. Tất cả những gì tôi muốn là chính xác là sự hiểu biết của tôi về cách chúng hoạt động để tôi có thể sử dụng chúng chính xác trong mã của mình.
Dưới đây là những điều tôi muốn hiểu rõ hơn:
Các quy tắc xác định khi nào một lệnh gọi hàm sẽ trả về một
list
(ví dụ:strsplit
biểu thức được đọc ở trên)?Nếu tôi không gán tên rõ ràng cho một
list
(ví dụlist(10,20,30,40)
:) là tên mặc định chỉ là số nguyên liên tiếp bắt đầu bằng 1? (Tôi giả sử, nhưng tôi không chắc chắn rằng câu trả lời là có, nếu không chúng ta sẽ không thể ép buộc loại nàylist
với một vectơ với một cuộc gọi đếnunlist
.)Tại sao hai toán tử khác nhau này
[]
, và[[]]
, trả về cùng một kết quả?x = list(1, 2, 3, 4)
cả hai biểu thức trả về "1":
x[1]
x[[1]]
Tại sao hai biểu thức này không trả về cùng một kết quả?
x = list(1, 2, 3, 4)
x2 = list(1:4)
Xin đừng chỉ cho tôi Tài liệu R ( ?list
, R-intro
) - Tôi đã đọc kỹ và nó không giúp tôi trả lời loại câu hỏi tôi đã đọc ở trên.
(cuối cùng, gần đây tôi đã biết và bắt đầu sử dụng Gói R (có sẵn trên CRAN) được gọi là hash
thực hiện hành vi loại bản đồ thông thường thông qua lớp S4; tôi chắc chắn có thể đề xuất Gói này.)
list
trong R của bạn không giống như hàm băm. Tôi có một cái nữa mà tôi nghĩ là đáng lưu ý. list
trong R có thể có hai thành viên có cùng tên tham chiếu. Xem xét điều đó obj <- c(list(a=1),list(a=2))
là hợp lệ và trả về một danh sách có hai giá trị được đặt tên là 'a'. Trong trường hợp này, một lệnh gọi obj["a"]
sẽ chỉ trả về phần tử danh sách phù hợp đầu tiên. Bạn có thể nhận hành vi tương tự (có thể giống hệt nhau) để băm với chỉ có một mục mỗi tên tham chiếu sử dụng môi trường trong R. ví dụx <- new.env(); x[["a"]] <- 1; x[["a"]] <- 2; x[["a"]]
x = list(1, 2, 3, 4)
, cả hai điều này KHÔNG trả về cùng một kết quả:x[1]
vàx[[1]]
. Cái đầu tiên trả về một danh sách và cái thứ hai trả về một vectơ số. Cuộn xuống bên dưới tôi thấy rằng Dirk là người duy nhất trả lời chính xác câu hỏi này.