2013-04-23 20 views
5

Tôi có một danh sách các khung dữ liệu, và muốn loại bỏ những người có ít hơn 2 hàng khỏi mylist:R loại bỏ các đối tượng từ một danh sách với nếu else

a<-data.frame(x=c(1:4),y=c("m", "n", "o", "p")) 
b<-data.frame(x=c(2:6),y=c("q", "w", "e", "r", "t")) 
c<-data.frame(x=c(6,7),y=c("j","k"),z=c("$","#")) 
d<-data.frame(x="9",y="q",z="+") 
mylist<-list(a,b,c,d) 

for (i in length(mylist)){ 
if (nrow(mylist[[i]])<=2){ 
mylist<-mylist[-i] 
} 
else{ 
mylist<-myslit 
}} 

Tuy nhiên nó chỉ có vẻ để loại bỏ dữ liệu .frame d. Khung dữ liệu c vẫn nằm trong "danh sách của tôi" sau khi chạy vòng lặp for.

+0

+1 cho hiển thị những gì bạn đã cố gắng, và cung cấp một ví dụ làm việc. –

Trả lời

8

Bạn có thể làm điều này dễ dàng hơn sử dụng một vòng lặp áp dụng:

row_lt2 <- which(sapply(mylist, nrow) < 2) 
mylist[-row_lt2] 
[[1]] 
    x y 
1 1 m 
2 2 n 
3 3 o 
4 4 p 

[[2]] 
    x y 
1 2 q 
2 3 w 
3 4 e 
4 5 r 
5 6 t 

[[3]] 
    x y z 
1 6 j $ 
2 7 k # 

Thông báo tôi sử dụng chỉ mục tiêu cực để loại bỏ mặt hàng thay vì chọn họ.

+0

Cảm ơn bạn rất nhiều. Nó hoạt động rất đẹp. : D – lamushidi

+0

Tôi thực sự yêu sự biểu cảm của giải pháp chức năng này có lợi cho phong cách bắt buộc hơn bằng cách sử dụng vòng lặp for. Đó là ngắn hơn nhiều, trong dễ hiểu hơn theo ý kiến ​​của tôi. –

+0

@PaulHiemstra Tôi đồng ý về tính biểu cảm của phong cách chức năng. Điều này có thể được thực hiện ngay cả đối với gọn gàng với chức năng 'Bộ lọc'. (Xem câu trả lời của tôi dưới đây.) –

3

Bạn không thể thực hiện quy trình này bằng cách sử dụng for vì chỉ mục thay đổi. Sử dụng for, sau khi loại bỏ dòng 2, bạn sẽ kiểm tra dòng 3, nhưng bạn cần kiểm tra lại dòng 2 (vì dòng 2 không giống với dòng trước đây). Thay đổi nó thành repeat hoặc while.

a<-data.frame(x=c(1:4),y=c("m", "n", "o", "p")) 
b<-data.frame(x=c(2:6),y=c("q", "w", "e", "r", "t")) 
c<-data.frame(x=c(6,7),y=c("j","k"),z=c("$","#")) 
d<-data.frame(x="9",y="q",z="+") 
mylist<-list(a,b,c,d) 

i <- 1 
while (i <= length(mylist)) { 
if (nrow(mylist[[i]])<=2){ 
    mylist<-mylist[-i] 
} 
else{ 
    i <- i+1 
} 
} 

Hoặc chỉ cần sử dụng giải pháp @ Paul ...: P

+0

Tôi chỉ bỏ qua gợi ý của OP, nhưng bạn hoàn toàn đúng rằng vòng lặp for không thực sự hữu ích ở đây. –

+1

@PaulHiemstra sẽ luôn luôn vượt trội, nhưng 'for' cũng có thể được sử dụng, xem câu trả lời của tôi –

+0

Mặc dù bạn có một cách tiếp cận khác so với OP, tạo một phương pháp mới loại trừ các kết quả phù hợp, thay vì xóa các kết quả phù hợp danh sách. –

3

Paul đã cung cấp một câu trả lời đã có, nhưng sai lầm của bạn chưa được chỉ ra.

Mã của bạn có hai vấn đề. Trước tiên, bạn cần phải cung cấp một phạm vi để lặp của bạn:

for (i in 1:length(mylist)) 

hoặc for (i trong seq_along (chiều dài (mylist)))

Nếu không có này, khởi tạo của bạn trông giống như for (i in 4) sau khi đánh giá, có nghĩa là chỉ có một lần lặp được chạy, loại bỏ phần tử 4 và thậm chí không xem xét tất cả các phần tử trước đó.

Tuy nhiên, nếu bạn khắc phục sự cố đó, một vấn đề khác sẽ xuất hiện. Cụ thể, danh sách của bạn không còn có 4 phần tử sau khi xóa phần tử 3. Phần tử chỉ có 3 phần tử, trong khi chỉ mục i của bạn sẽ tăng lên đến 4, dẫn đến lỗi subscript out of bounds.

Do đó, người ta chỉ có thể đề xuất phương pháp tiếp cận bằng cách áp dụng, như được mô tả bởi @Paul.

Ngoài ra, trái ngược với sự khẳng định nếu không, nó có thể đạt được cùng sử dụng for vòng lặp, chỉ cách tiếp cận của bạn cần phải được hơi khác nhau:

for (i in 1:length(mylist)) { 
    if (nrow(mylist[[i]])>2) 
    { 
     mylist2[i]<-mylist[i] 
    } 
} 
print(mylist2) 

Ở đây bạn chọn các yếu tố danh sách đó là lớn hơn 2, và gán chúng vào danh sách mới. Sapply sẽ nhanh hơn.

+0

+1 giải pháp tốt đẹp bằng cách sử dụng vòng lặp 'for'. Nếu 'mylist' là lớn, bạn có thể preallocate nó đầu tiên, tiết kiệm rất nhiều bộ nhớ và thời gian. –

+0

@PaulHiemstra Tôi không thấy làm thế nào người ta có thể xác định kích thước của mylist2 ở đây, ngoại trừ bằng cách sử dụng cách tiếp cận của bạn, mà ám toàn bộ vòng lặp lỗi thời :) –

+0

Cảm ơn đã chỉ ra sự khác biệt giữa '(i in length (mylist))' và '(i trong 1: length (mylist))'. Một lỗi thường gặp mà tôi thường mắc phải. – lamushidi

4

Để thêm vào các câu trả lời khác: đây chính là loại điều các bậc cao Filter chức năng được thực hiện cho:

> Filter(function(x) {nrow(x) >= 2}, mylist) 
[[1]] 
    x y 
1 1 m 
2 2 n 
3 3 o 
4 4 p 

[[2]] 
    x y 
1 2 q 
2 3 w 
3 4 e 
4 5 r 
5 6 t 

[[3]] 
    x y z 
1 6 j $ 
2 7 k # 
+0

WOW, ** Chức năng lọc ** tuyệt vời. Cảm ơn bạn!!! – lamushidi

+0

@lamushidi Không sao cả. Hãy xem các chức năng khác có sẵn trên cùng trang trợ giúp dưới dạng '? Bộ lọc'. Chúng có thể khá hữu ích. –