在文本列表中提取唯一值,其中每个项目具有恒定的公共前缀或后缀或两者兼有

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 &lt;- 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 &lt;- 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

你也可以给出几个模式,依次尝试,这里我们有NAs,因为后缀在类型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 好吧,如果您的实际前缀包含数字但从未以它们结尾(例如,它们以下划线结尾),我们可以找到一个很好的解决方案。但如果您的解决方案有效,那就太好了。 我认为前缀和后缀可以通过编程方式找到,因为它们在所有元素中都是不变的。我的回答解决了这个问题,但是当没有后缀时以某种方式失败

以上是关于在文本列表中提取唯一值,其中每个项目具有恒定的公共前缀或后缀或两者兼有的主要内容,如果未能解决你的问题,请参考以下文章

BASEX - 从变量中获取唯一值

Listview的项目位置0持有另一个列表视图,其中包含10个项目,每个项目打开单个活动但不同的文本数据

UICollectionView 项目间距不是恒定的

提取 2 个集合/文件之间的唯一值

如何使用linq / lambda计算具有唯一属性的列表中的对象数?

熊猫数据框:在固定其他列的列中提取具有特定标准/条件最小值的数据[重复]