我對 R 很陌生,我正在嘗試撰寫代碼來解決 NYTimes 網站上的 Spelling Bee 游戲,看看我在做什么。我嘗試撰寫一個函式來比較兩個字串('given' 和 'test_word'),如果你可以只用來自 'given' 的字母拼寫'test_word',則回傳 TRUE,否則回傳 FALSE。我得到了它的作業,所以我下載了 enable1 單詞表并嘗試將該功能應用于串列中的每個單詞。它沒有在資料框中給我一個新列,其中包含每個單詞的函式結果,它只是為每一行回傳 FALSE,我只是對自己做錯了什么感到困惑。看起來它只是為單詞串列中的第一個條目獲取函式的值,而不是單獨查看每個單詞。
這是我的代碼:
library(dplyr)
is_good <- function(given, test_word) {
diffs <- paste(unlist(setdiff(strsplit(test_word,'')[[1]],strsplit(given,'')[[1]])),collapse='')
match = case_when(
diffs == '' ~ TRUE,
diffs != '' ~ FALSE
)
return(match)
}
given <- 'CLEXION'
#words = read.csv('c:/Users/Dave/Documents/R/enable1.txt', header=FALSE)
# edited to add sample list of words
V1 <- c('AAHED','LEXICON','LION','COLLECTION')
words <- data.frame(V1)
names(words) <- c('word')
words <- filter(words, nchar(word)>=4)
words$word <- toupper(words$word)
words <- words %>% mutate(is_match = is_good(given,word))
運行所有這些后,我得到以下輸出:
> filter(words, is_match == TRUE)
[1] word is_match
<0 rows> (or 0-length row.names)
只是為了檢查我對一個我知道應該有效并得到的詞運行了過濾器
> filter(words, word=='LEXICON')
word is_match
1 LEXICON FALSE
如果我用一個詞單獨運行該函式,我會得到預期的結果:
> is_good(given,'LEXICON')
[1] TRUE
為什么我的變異步驟中的函式呼叫沒有將函式應用于每一行?我對串列和資料框的想法感到滿意,但是在將其付諸實踐時顯然我缺少一些東西。
更新:我研究了 lapply 函式,它做了我希望的事情——我的新代碼看起來像
test_split <- lapply(test_word, function(w) {strsplit(w,'')[[1]]})
given_split <- strsplit(given,'')[[1]]
diff_1 <- lapply(test_split, function(x) {paste(unlist(setdiff(x, given_split)),collapse='')})
match = lapply(diff_1, function(x) {
case_when(
x == '' ~ TRUE,
x != '' ~ FALSE
)})
uj5u.com熱心網友回復:
答案與OP的觀點相匹配
is_good <- function(given, test_word) {
test_split <- strsplit(test_word, split = "") # don't need lapply here since strsplit is already vectorized
given_split <- strsplit(given,'')[[1]]
diff_1 <- lapply(test_split, function(x) {paste(unlist(setdiff(x, given_split)),collapse='')})
# From here, it is back to simple things!
diff_1 <- unlist(diff_1)
match <- diff_1 == ""
return(match)
}
感謝您提供示例資料。它更容易解決。
這可能是矯枉過正,但這是 dplyr / tidyverse 答案。
請注意,這|>是基管(類似于%>%)。(適用于 R>=4.1.0)
請注意,您將需要額外的軟體包(stringr 和 tidyr)。檢查您是否安裝了它們。
如果尚未安裝,請運行
install.packages(c("tidyr", "stringr")
purrr::map()用于操作串列的元素
purrr::map_lgl()確保您回傳一個邏輯向量
處理重復字母的解決方案
library(dplyr)
is_good <- function(given, test_word) {
# Standardizing to upper case
given <- toupper(given)
test_word <- toupper(test_word)
# Extracting letters
given_letters <- stringr::str_split(given, pattern = "")
given_letters <- unlist(given_letters)
# This part deals with duplicated letters
# there is probably a base R way to do it.
given_letters <- tibble(given_letter = given_letters) |>
group_by(given_letter) |>
mutate(letter = paste0(given_letter, row_number())) |>
pull(letter)
# For word "DREAD", it will return ("D1", "R1", "E1", "D2")
# Manipulating test_word
letters_in_test_words <- stringr::str_split(test_word, pattern = "")
# a little bit more complicated, but similar to previously to mark duplicated
# letters. It outputs a list. Example: for input "THIN", "MINI"
# a list of 2
# [[1]] : "T1", "H1", "I1", "N1"
# [[2]] : "M1", "I1", "N1" "I2"
letters_in_test_words <- tibble(
word_id = 1:length(letters_in_test_words),
letter = letters_in_test_words
) |>
tidyr::unnest(letter) |>
group_by(word_id, letter) |>
mutate(letter = paste0(letter, dplyr::row_number())) |>
ungroup() |>
tidyr::nest(data = letter) |>
mutate(data = purrr::map(data, 1)) |>
pull(data)
# iterates over the words to find if there is a complete match
match <- purrr::map_lgl(letters_in_test_words, ~ all(.x %in% given_letters))
match
}
given <- 'CLEXION'
#words = read.csv('c:/Users/Dave/Documents/R/enable1.txt', header=FALSE)
# edited to add sample list of words
V1 <- c('AAHED','LEXICON','LION','COLLECTION')
words <- data.frame(word = V1)
words <- filter(words, nchar(word)>=4)
words$word <- toupper(words$word) # a good idea to be put inside the function
is_good("AHMED","LEXICO1N")
#> [1] FALSE
words <- words %>% mutate(is_match = is_good(given,word))
words |>
filter(is_match)
#> word is_match
#> 1 LEXICON TRUE
#> 2 LION TRUE
# My solution checks for duplicated letters
# You probably don't want this as TRUE.
is_good(given = "TRUCE", test_word = "TRUCEE")
#> [1] FALSE
由reprex 包于 2022-06-17 創建(v2.0.1)
注意:我的函式可能也存在于基礎 R 中,但我更擅長使用表格。這也是矯枉過正,因為它檢查重復。
不檢查重復項的解決方案(更簡單)
library(dplyr)
is_good <- function(given, test_word) {
# Standardizing
given <- toupper(given)
test_word <- toupper(test_word)
# Extracting letters
given_letters <- stringr::str_split(given, pattern = "")
given_letters <- unlist(given_letters)
# Manipulating test_word
letters_in_test_words <- stringr::str_split(test_word, pattern = "")
# a little bit more complicated, but simi
# iterates over the words to find if there is a complete match
match <- purrr::map_lgl(letters_in_test_words, ~ all(.x %in% given_letters))
match
}
given <- 'CLEXION'
#words = read.csv('c:/Users/Dave/Documents/R/enable1.txt', header=FALSE)
# edited to add sample list of words
V1 <- c('AAHED','LEXICON','LION','COLLECTION')
words <- data.frame(word = V1)
words <- filter(words, nchar(word)>=4)
words$word <- toupper(words$word) # a good idea to be put inside the function
is_good("AHMED","LEXICO1N")
#> [1] FALSE
words <- words %>% mutate(is_match = is_good(given,word))
words |>
filter(is_match)
#> word is_match
#> 1 LEXICON TRUE
#> 2 LION TRUE
# You probably don't want this as TRUE. but it will come out as TRUE without the
# Duplicated letters are ignored.
is_good(given = "TRUCE", test_word = "TRUCEE")
#> [1] TRUE
由reprex 包于 2022-06-17 創建(v2.0.1)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/492590.html
