R语言Codewars实战——Help the bookseller !(6kyu)

Description:

A bookseller has lots of books classified in 26 categories labeled A, B, ..., Z. Each book has a code c of 3, 4, 5 or more characters. The 1st character of a code is a capital letter which defines the book category.

In the bookseller’s stocklist each code c is followed by a space and by a positive integer n (int n >= 0) which indicates the quantity of books of this code in stock.

For example an extract of a stocklist could be:

L = {"ABART 20", "CDXEF 50", "BKWRK 25", "BTSQZ 89", "DRTYM 60"}.
or
L = ["ABART 20", "CDXEF 50", "BKWRK 25", "BTSQZ 89", "DRTYM 60"] or ....

You will be given a stocklist (e.g. : L) and a list of categories in capital letters e.g :

M = {"A", "B", "C", "W"} 
or
M = ["A", "B", "C", "W"] or ...

and your task is to find all the books of L with codes belonging to each category of M and to sum their quantity according to each category.

For the lists L and M of example you have to return the string (in Haskell/Clojure/Racket a list of pairs):

 (A : 20) - (B : 114) - (C : 50) - (W : 0)

where A, B, C, W are the categories, 20 is the sum of the unique book of category A, 114 the sum corresponding to “BKWRK” and “BTSQZ”, 50 corresponding to “CDXEF” and 0 to category ‘W’ since there are no code beginning with W.

If L or M are empty return string is "" (Clojure and Racket should return an empty array/list instead).

Note:

In the result codes and their values are in the same order as in M.

测试案例

listOfArt = c("BBAR 150", "CDXE 515", "BKWR 250", "BTSQ 890", "DRTY 600", "XRAV 1")
listOfCat = c("A", "B", "C", "D")
stockList(listOfArt,listOfCat)

[1] "(A : 0) - (B : 1290) - (C : 515) - (D : 600)"

我的代码

stockList <- function(listOfArt, listOfCat) {
  if (length(listOfArt)*length(listOfCat) == 0) return("")
  result.split <- sapply(listOfArt, function(bookcode){return(list(name=unlist(strsplit(bookcode, split=""))[1],num=as.integer(gsub('[^0-9]',"", bookcode))))})
  paste0(sapply(listOfCat, function(cat){paste0(c("(",cat," : ",sum(unlist(result.split[2,grep(cat,result.split[1,])])),")"),collapse = "")}),collapse = " - ")
}

这段代码有以下几点需要解释说明一下:

  • 在计算result.split的过程中,由于我的构想是对每一个listOfArt中的字符串,都能够返回首字母以及当中的数字,这就有两个返回了。这里我觉得sapply函数比较好的一点是,它会把函数返回的列表中所有的第一个元素放在一起,同理第二个、第三个等也会相应地放到一起,这就是之后的调用变得非常方便,比如调用所有的name只需result.split[1, ]即可。
  • 在用strsplit函数处理完字符串之后,还需要使用unlist函数将得到的结果转为向量,当然也可以用strsplit()[[1]]调用,需要注意的是,一定要是’[[1]]’,里面不能是1以外的数字。
  • gsub函数的第一个参数是'[^0-9]',这个是正则表达式,目的是在函数第三个参数中匹配非0-9的内容,并将它们替换为第二个参数的"",进而整个字符串将只剩下0-9的数字,接着使用as.integer将得到的数字字符转为数字。
  • 再讲讲grep函数,这个函数会返回匹配的所有结果对应的下标索引。而grepl则是所有匹配结果都为TRUE,其余的则为FALSE,得到一个与被匹配对象同长度的逻辑值向量。此外,match函数是返回匹配出的第一个结果的下标索引,这与grep有所不同。
  • 最后讲讲paste函数,这个函数有两个需要注意的参数——seqcollapseseq参数是设置字符合并时两个字符之间用什么隔开,paste0函数默认seq="",也就是合并的字符之间是无缝连接的。collapse参数设置的是是否应该将所有字符合并的结果再进一步地综合到一个字符串中去,如果综合到一起,应该用什么去分割开所有的字符。在本问中我将collapse参数设置为-,意思是将得到的所有字符合并结果再用-连接起来变成一个字符串。

别人的代码

stockList <- function(L, M) {
  if (length(L)*length(M) == 0) return("")
  r <- sapply(M, function(v) sprintf("(%s : %s)",v, sum(as.numeric(gsub("\\D+","",L[grep(paste0("^",v),L,perl = TRUE)])))))
  paste0(r,collapse = " - ")
}

这里让我比较惊讶的是直接用sprintf的结果竟然可以作为函数的返回值,其次是直接使用^character的形式匹配首字母为character的字符串,这比我的代码效率高多了,需要注意的是,这里面的perl = TRUE可以去除的,得到的结果会是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三只佩奇不结义

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值