在文本列表中提取唯一值,其中每个项目具有恒定的公共前缀或后缀或两者兼有
Posted
技术标签:
【中文标题】在文本列表中提取唯一值,其中每个项目具有恒定的公共前缀或后缀或两者兼有【英文标题】:Extract unique values within text list, where each item has constant common prefix or suffix or both 【发布时间】:2022-01-19 14:09:22 【问题描述】:我有一组具有不同前缀和后缀的变量。有两种类型。一种类型只有前缀。第二种类型有前缀,然后是数字,然后是后缀。每种类型中的数字都是无序的。这是这两种类型的一些示例代码
VarNamesType1 <- c("Prefix12", "Prefix11", "Prefix144", "Prefix122")
VarNamesType1>
[1] "Prefix12" "Prefix11" "Prefix144" "Prefix122"
这里是带前缀和后缀的变量名
VarNamesType2 <- c("Pre29Suffix","Pre23Suffix2" "Pre25Suffix2","Pre27Suffix2" )
VarNamesType2>
[1] "Pre29Suffix" "Pre23Suffix2" "Pre25Suffix2" "Pre27Suffix2"
有没有办法在这些变量类型列表中找到唯一值。因此,对于 VarNamesType1,使用代码查找值 2、1、44、22,对于 VarNamesType2,使用代码查找 9、3、5、7。是否可以使用相同的代码找到两种类型的唯一编号?任何想法或建议将不胜感激。谢谢
EDIT1-感谢发布解决方案的海报删除所有文本。但是前缀和后缀也可以包含数字。因此,删除文本将不起作用。我已经更新了示例代码。
EDIT2- 我现在可以使用它来查找前缀部分。我不知道如何找到后缀部分。
find_common_start <- function(strings)
max_length = min(nchar(strings))
for(len in max_length:1)
if(length(unique(substr(strings, start = 1, stop = len))) == 1)
return(substr(strings[[1]], start = 1, stop = len))
> find_common_start(VarNamesType1)
[1] "Prefix1"
find_common_start(VarNamesType2)
[1] "Pre2"
这个可以适配做后缀吗?
EDIT3 - 通过写在最后解决它
find_unique <- function(FindUnique)
max_presuffix = min( nchar( FindUnique ) )
for ( i in 1:max_presuffix )
if( length( unique( substr( FindUnique , start = 1, stop = i) ) ) == 1 )
prefix <-(substr( FindUnique[[1]], start = 1, stop = i ))
if( length( unique( substr( FindUnique, start = nchar(FindUnique) - i , stop = nchar( FindUnique ) ) ) ) == 1 )
suffix <-(substr( FindUnique[[1]], start = nchar( FindUnique )- i , stop = nchar( FindUnique )[1] ) )
if (exists("prefix")) FindUnique <- sub( prefix ,"", FindUnique )
if (exists("suffix"))FindUnique <- sub( suffix ,"", FindUnique )
return( FindUnique )
> find_unique(VarNamesType1)
[1] "2" "1" "44" "22"
> find_unique(VarNamesType2)
[1] "9" "3" "5" "7"
【问题讨论】:
删除所有字母,应该留下数字。那么问题来了,数字总是有前缀和后缀吗? 通用前缀和后缀,可以包含数字。谢谢 【参考方案1】:我们可以使用readr::parse_number
,或者删除所有字母或使用正则表达式提取所有数字。
与parse_number
readr::parse_number(VarNamesType1)
[1] 2 1 44 22
readr::parse_number(VarNamesType2)
[1] 9 3 5 7
使用正则表达式
stringr::str_extract(VarNamesType2, '\\d+') |>
as.integer()
[1] 9 3 5 7
示例数据中的所有值都已经是唯一的,但如果我们对任何数据集的唯一值感兴趣,我们可以将输出通过管道传输到 unique()
,如下所示:
readr::parse_number(VarNamesType1) |> unique()
编辑
OP 告知后缀和前缀可能有数字。 在这种情况下, parse_number() 将不起作用,我们将不得不使用基于正则表达式的方法。
我们必须有一致的“前缀”或“后缀”模式才能做到这一点。我们可以使用 stringr::str_remove_all
来删除前缀或后缀,并用“|”折叠它们:
library(glue)
library(stringr)
prefix<-'Pre2'
suffix<-'Suffix2'
str_remove_all(VarNamesType2, glue('^prefix|suffix$')) |>
as.integer()
[1] 9 3 5 7
【讨论】:
我认为我们应该先等待 OP 确认输入是否正确。如果确实只是用字母包裹的数字,那么这篇文章就是重复的。 谢谢,但如果前缀或后缀包含数字,这将不起作用。 是的,它没有。请提供前缀或后缀的模式,如果没有,我们将无能为力。请提供一个适当的可重现示例,带有几个不同的前缀和后缀。 我刚刚更新了我的示例代码,谢谢 好的,请看更新后的答案【参考方案2】:我终于明白了这个问题。
要检查隐藏在常量(前缀和后缀)之间的唯一值,
我们可以先将字符串拆分为单个字符,然后使用 purrr::pmap
删除长度 ==1 的列表元素
library(purrr)
pmap(strsplit(VarNamesType2, ''), ~unique(c(...)))%>%
keep(~length(.x) > 1) %>%
unlist()%>%
as.integer()
[1] 9 3 5 7
【讨论】:
我按原样剪切和粘贴,并收到此错误错误:.l
的元素 1 的长度必须为 1 或 13,而不是 12
我无法重现此问题。您是否使用相同的数据? VarNamesType2 <- paste0( "Pre2" , c(9,3,5,7) , "Suffix2")
也许您的数据有 NA?
是的,我正在使用 VarNamesType2
只是发出咕噜声。它在新的 r 会话中运行顺利,只加载了 purrr
包。【参考方案3】:
我最终写了这个,它回答了我自己的问题。
find_unique <- function(FindUnique)
max_presuffix = min( nchar( FindUnique ) )
for ( i in 1:max_presuffix )
if( length( unique( substr( FindUnique , start = 1, stop = i) ) ) == 1 )
prefix <-(substr( FindUnique[[1]], start = 1, stop = i ))
if( length( unique( substr( FindUnique, start = nchar(FindUnique) - i , stop = nchar( FindUnique ) ) ) ) == 1 )
suffix <-(substr( FindUnique[[1]], start = nchar( FindUnique )- i , stop = nchar( FindUnique )[1] ) )
if (exists("prefix")) FindUnique <- sub( prefix ,"", FindUnique )
if (exists("suffix"))FindUnique <- sub( suffix ,"", FindUnique )
return( FindUnique )
> find_unique(VarNamesType1)
[1] "2" "1" "44" "22"
> find_unique(VarNamesType2)
[1] "9" "3" "5" "7"
【讨论】:
如果提供的VarNamesType2
不是带有88 的最后一个元素,为什么返回c(9, 3, 5, 7, 88)
?您提供的数据是 VarNamesType2 <- paste0( "Pre2" , c(9,3,5,7) , "Suffix2")
,它有 4 个元素,而这个答案的输出表明有 5 个元素
对不起,我正在使用 VarNamesType2
现在我可以用我的回答重现您的错误。会努力的【参考方案4】:
一个有效的(虽然是一个但令人费解的)tidyverse 答案。
这依赖于将字符串拆分为单个字符的列表,然后查找在自然顺序(前缀)和rev()
erse 顺序(后缀)中只有一个唯一值的连续字符位置的数量
library(dplyr)
library(stringr)
library(purrr)
library(data.table)
library(tidyr)
splitted_strings<-list(
strsplit(VarNamesType2, ''),
rev_char_list = map(strsplit(VarNamesType2, ''), rev)
)
indexes<-splitted_strings %>%
map_int(., \(x) sum(
x %>%
tibble(temp = .) %>%
unnest_wider(temp)%>%
map_int(~length(unique(.x))) %>%
data.table::rleid(.)==1
)) %>%
set_names(c('prefix', 'suffix'))
str_sub(VarNamesType2,
start = indexes['prefix']+1,
end = -(indexes['suffix']+1))
[1] "9" "3" "5" "7" "88"
【讨论】:
+ ) unnest_wider(., temp) 中的错误:找不到函数“unnest_wider” 它需要 library(tidyr) 才能使其工作。谢谢 我稍微简化了代码,最初的答案是缺少库(tidyr),正如您已经指出的那样。 它对 VarNamesType2 和 VarNamesType1 都不起作用,如果在第一个替换中会发生这种情况 > str_sub(VarNamesType2, nchar_prefix+1, -(nchar_suffix+1)) [1] "" "" """"【参考方案5】:您可以使用 unglue:
VarNamesType1 <- paste0("Prefix1" , c(2,1,44,22))
VarNamesType2 <- paste0( "Pre2" , c(9,3,5,7) , "Suffix2")
# parse all your strings and extract the info in a table
pattern <- "prefix=Prefix1|Pre2n=\\d+suffix"
df <- unglue::unglue_data(
c(VarNamesType1, VarNamesType2), pattern, convert = TRUE)
df
#> prefix n suffix
#> 1 Prefix1 2
#> 2 Prefix1 1
#> 3 Prefix1 44
#> 4 Prefix1 22
#> 5 Pre2 9 Suffix2
#> 6 Pre2 3 Suffix2
#> 7 Pre2 5 Suffix2
#> 8 Pre2 7 Suffix2
df$n
#> [1] 2 1 44 22 9 3 5 7
你也可以给出几个模式,依次尝试,这里我们有NA
s,因为后缀在类型1中不存在,而不是""
patterns <- c("prefix=Prefix1n", "prefix=Pre2nsuffix=Suffix2")
unglue::unglue_data(
c(VarNamesType1, VarNamesType2), patterns, convert = TRUE)
#> prefix n suffix
#> 1 Prefix1 2 <NA>
#> 2 Prefix1 1 <NA>
#> 3 Prefix1 44 <NA>
#> 4 Prefix1 22 <NA>
#> 5 Pre2 9 Suffix2
#> 6 Pre2 3 Suffix2
#> 7 Pre2 5 Suffix2
#> 8 Pre2 7 Suffix2
由reprex package (v2.0.1) 于 2021-12-17 创建
【讨论】:
我想我用代码 VarNamesType1 通过查看 Pre234something,您无法可靠地知道前缀是 Pre2 还是 Pre23。如果有一些东西可以可靠地定义前缀,我们可以找到解决方案 我知道这不会是完整的证据。我知道很难得到我想要的东西。我首先从文本的前缀和后缀开始。所以我收到了删除文本的解决方案。我使用的变量往往是问卷类型,例如。 Qnumber_rowN_columnN。这些是我发现的典型模式: Type1 好吧,如果您的实际前缀包含数字但从未以它们结尾(例如,它们以下划线结尾),我们可以找到一个很好的解决方案。但如果您的解决方案有效,那就太好了。 我认为前缀和后缀可以通过编程方式找到,因为它们在所有元素中都是不变的。我的回答解决了这个问题,但是当没有后缀时以某种方式失败以上是关于在文本列表中提取唯一值,其中每个项目具有恒定的公共前缀或后缀或两者兼有的主要内容,如果未能解决你的问题,请参考以下文章
Listview的项目位置0持有另一个列表视图,其中包含10个项目,每个项目打开单个活动但不同的文本数据