我可以使用循环来解决这个问题,但我正在尝试在向量中思考,因此我的代码将更加R-esque。
我有一个名单。格式为firstname_lastname。我想从这个列表中删除一个只有名字的单独列表。我似乎无法理解如何做到这一点。这是一些示例数据:
t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- strsplit(t,"_")
看起来像这样:
> tsplit
[[1]]
[1] "bob" "smith"
[[2]]
[1] "mary" "jane"
[[3]]
[1] "jose" "chung"
[[4]]
[1] "michael" "marx"
[[5]]
[1] "charlie" "ivan"
我可以使用这样的循环得到我想要的东西:
for (i in 1:length(tsplit)){
if (i==1) {t_out <- tsplit[[i]][1]} else{t_out <- append(t_out, tsplit[[i]][1])}
}
这会给我这个:
t_out
[1] "bob" "mary" "jose" "michael" "charlie"
那么如何在没有循环的情况下做到这一点?
答案 0 :(得分:43)
还有一种方法:
t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
pieces <- strsplit(t,"_")
sapply(pieces, "[", 1)
在单词中,最后一行提取列表中每个组件的第一个元素,然后将其简化为向量。
这是如何工作的?好吧,你需要实现另一种写x[1]
的方式是"["(x, 1)
,即有一个名为[
的函数可以进行子集化。 sapply
调用适用于原始列表的每个元素调用此函数一次,传入两个参数,list元素和1。
这种方法优于其他方法的优点是,您可以从列表中提取多个元素,而无需重新计算拆分。例如,姓氏为sapply(pieces, "[", 2)
。一旦你习惯了这个习语,它就很容易阅读。
答案 1 :(得分:26)
您可以使用apply
(或sapply
)
t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
f <- function(s) strsplit(s, "_")[[1]][1]
sapply(t, f)
bob_smith mary_jane jose_chung michael_marx charlie_ivan
"bob" "mary" "jose" "michael" "charlie"
答案 2 :(得分:10)
怎么样:
tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
fnames <- gsub("(_.*)$", "", tlist)
# _.* matches the underscore followed by a string of characters
# the $ anchors the search at the end of the input string
# so, underscore followed by a string of characters followed by the end of the input string
用于RegEx方法?
答案 3 :(得分:9)
怎么样:
t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
sub("_.*", "", t)
答案 4 :(得分:7)
我怀疑这是最优雅的解决方案,但它胜过循环:
t.df <- data.frame(tsplit)
t.df[1, ]
将列表转换为数据帧是我能让他们做我想做的事情的唯一方法。我期待着能够真正理解如何处理列表的人阅读答案。
答案 5 :(得分:4)
你几乎拥有它。 真的只是
的问题*apply
函数循环显示现有列表,我通常从lapply
开始,有时会切换到sapply
strsplit(string, splitterm)
并且您需要奇怪的[[1]][1]
来挑选答案的第一个字段t
或c
和朋友)给出了
> tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
> fnames <- sapply(tlist, function(x) strsplit(x, "_")[[1]][1])
> fnames
bob_smith mary_jane jose_chung michael_marx charlie_ivan
"bob" "mary" "jose" "michael" "charlie"
>
答案 6 :(得分:3)
您可以使用unlist()
:
> tsplit <- unlist(strsplit(t,"_"))
> tsplit
[1] "bob" "smith" "mary" "jane" "jose" "chung" "michael"
[8] "marx" "charlie" "ivan"
> t_out <- tsplit[seq(1, length(tsplit), by = 2)]
> t_out
[1] "bob" "mary" "jose" "michael" "charlie"
可能有更好的方法只提取奇数索引条目,但无论如何你都没有循环。
答案 7 :(得分:2)
另一种方法,基于brentonk的非列表示例...
tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- unlist(strsplit(tlist,"_"))
fnames <- tsplit[seq(1:length(tsplit))%%2 == 1]
答案 8 :(得分:1)
我会使用以下基于unlist()的方法:
> t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
> tsplit <- strsplit(t,"_")
>
> x <- matrix(unlist(tsplit), 2)
> x[1,]
[1] "bob" "mary" "jose" "michael" "charlie"
这种方法的最大优点是它同时解决了姓氏的等效问题:
> x[2,]
[1] "smith" "jane" "chung" "marx" "ivan"
缺点是您需要确定所有名称都符合firstname_lastname
结构;如果没有,那么这种方法就会破裂。
答案 9 :(得分:0)
从开头给出的原始tsplit
列表对象开始,此命令将执行:
unlist(lapply(tsplit,function(x) x[1]))
它提取所有列表元素的第一个元素,然后将列表转换为矢量。首先取消列表到矩阵,然后提取第一列也没关系,但是你依赖于所有列表元素具有相同长度的事实。这是输出:
> tsplit
[[1]]
[1] "bob" "smith"
[[2]]
[1] "mary" "jane"
[[3]]
[1] "jose" "chung"
[[4]]
[1] "michael" "marx"
[[5]]
[1] "charlie" "ivan"
> lapply(tsplit,function(x) x[1])
[[1]]
[1] "bob"
[[2]]
[1] "mary"
[[3]]
[1] "jose"
[[4]]
[1] "michael"
[[5]]
[1] "charlie"
> unlist(lapply(tsplit,function(x) x[1]))
[1] "bob" "mary" "jose" "michael" "charlie"