Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 按id在行之间合并字符串_Regex_R_String_Merge - Fatal编程技术网

Regex 按id在行之间合并字符串

Regex 按id在行之间合并字符串,regex,r,string,merge,Regex,R,String,Merge,我希望通过id变量在行之间合并字符串。我知道如何使用下面的R代码。然而,我的代码似乎过于复杂 在本例中,每个字符串有两个不是点的元素。id中的每对连续行都有一个公共元素。因此,合并两行后,这些元素中只剩下一个 显示所需结果,下面的R代码返回所需结果。谢谢你的建议。很抱歉,我的R代码太长且复杂,但它确实有效,我的目标是在baseR中获得更高效的代码 my.data <- read.table(text = ' id my.string 2 11..

我希望通过id变量在行之间合并字符串。我知道如何使用下面的
R
代码。然而,我的代码似乎过于复杂

在本例中,每个字符串有两个不是点的元素。id中的每对连续行都有一个公共元素。因此,合并两行后,这些元素中只剩下一个

显示所需结果,下面的
R
代码返回所需结果。谢谢你的建议。很抱歉,我的
R
代码太长且复杂,但它确实有效,我的目标是在base
R
中获得更高效的代码

my.data <- read.table(text = '
     id         my.string
      2    11..................
      2    .1...2..............
      2    .....2...3..........
      5    ....................
      6    ......2.....2.......
      6    ............2...4...
      7    .1...2..............
      7    .....2....3.........
      7    ..........3..3......
      7    .............34.....
      8    ....1.....1.........
      8    ..........12........
      8    ...........2....3...
      9    ..................44
     10    .2.......2..........
     11    ...2...2............
     11    .......2.....2......
     11    .............2...2..
', header = TRUE, na.strings = 'NA', stringsAsFactors = FALSE)
my.data

desired.result <- read.table(text = '
     id         my.string
      2    11...2...3..........
      5    ....................
      6    ......2.....2...4...
      7    .1...2....3..34.....
      8    ....1.....12....3...
      9    ..................44
     10    .2.......2..........
     11    ...2...2.....2...2..
', header = TRUE, na.strings = 'NA', stringsAsFactors = FALSE)

# obtain position of first and last non-dot
# from: http://stackoverflow.com/questions/29229333/position-of-first-and-last-non-dot-in-a-string-with-regex

first.last.dot <- data.frame(my.data, do.call(rbind, gregexpr("^\\.*\\K[^.]|[^.](?=\\.*$)", my.data[,2], perl=TRUE)))

# obtain non-dot elements
first.last.dot$first.element <- as.numeric(substr(first.last.dot$my.string, first.last.dot$X1, first.last.dot$X1))
first.last.dot$last.element  <- as.numeric(substr(first.last.dot$my.string, first.last.dot$X2, first.last.dot$X2))

# obtain some book-keeping variables
first.last.dot$number.within.group <- sequence(rle(first.last.dot$id)$lengths)
most.records.per.id                <- max(first.last.dot$number.within.group)
n.ids                              <- length(unique(first.last.dot$id))

# create matrices for recording data
positions.per.id <- matrix(NA, nrow = (n.ids), ncol=(most.records.per.id+1))
values.per.id    <- matrix(NA, nrow = (n.ids), ncol=(most.records.per.id+1))

# use nested for-loops to fill matrices with data
positions.per.id[1,1] = first.last.dot$X1[1]
   values.per.id[1,1] = first.last.dot$first.element[1]

positions.per.id[1,2] = first.last.dot$X2[1]
   values.per.id[1,2] = first.last.dot$last.element[1]

j = 1

for(i in 2:nrow(first.last.dot)) {

     if(first.last.dot$id[i] != first.last.dot$id[i-1]) j = j + 1

      positions.per.id[j, (first.last.dot$number.within.group[i]+0)] = first.last.dot$X1[i]
      positions.per.id[j, (first.last.dot$number.within.group[i]+1)] = first.last.dot$X2[i]

      values.per.id[j, (first.last.dot$number.within.group[i]+0)] = first.last.dot$first.element[i]
      values.per.id[j, (first.last.dot$number.within.group[i]+1)] = first.last.dot$last.element[i]
}

# convert matrix data into new strings using nested for-loops
new.strings <- matrix(0, nrow = nrow(positions.per.id), ncol = nchar(my.data$my.string[1]))

for(i in 1:nrow(positions.per.id)) {
     for(j in 1:ncol(positions.per.id)) {

          new.strings[i,positions.per.id[i,j]] <- values.per.id[i,j]
     }
}

# format new strings
new.strings[is.na(new.strings)] <- 0
new.strings[new.strings==0]     <- '.'

new.strings2 <- data.frame(id = unique(first.last.dot$id), my.string = (do.call(paste0, as.data.frame(new.strings))), stringsAsFactors = FALSE)
new.strings2

all.equal(desired.result, new.strings2)
# [1] TRUE

my.data在base R中这样做有点受虐狂,所以我不会这么做,但只要有点毅力,你可以自己做。这是一个
数据表
版本(您需要从
github
安装最新的1.9.5版本才能获得
tstrsplit
):


伙计,这很难。请不要让我解释我做了什么

data.frame(id=unique(my.data$id), my.string=sapply(lapply(unique(my.data$id), function(id) gsub('^$','.',substr(gsub('\\.','',do.call(paste0,strsplit(my.data[my.data$id==id,'my.string'],''))),1,1)) ), function(x) paste0(x,collapse='') ), stringsAsFactors=F );

好的,我来解释一下:

它以这个
lappy()
调用开始:

lapply(unique(my.data$id), function(id) ... )
如您所见,上面的代码基本上迭代data.frame中的唯一ID,依次处理每个ID。以下是函数的内容:

gsub('^$','.',substr(gsub('\\.','',do.call(paste0,strsplit(my.data[my.data$id==id,'my.string'],''))),1,1))
让我们把它分成几部分,从最里面的子表达式开始:

strsplit(my.data[my.data$id==id,'my.string'],'')
do.call(paste0,...)
以上为当前
id
值的所有
my.string
单元格编制索引,并使用
strsplit()
拆分每个字符串。这将生成字符向量的
列表
,每个列表组件包含一个字符串向量,其中整个向量对应于被拆分的输入字符串。使用空字符串作为分隔符会导致每个输入字符串中的每个单独字符成为对应于所述输入字符串的列表组件中的输出向量中的一个元素

下面是上面表达式生成的示例(对于id==2):

上面的
strsplit()
调用包含在以下内容中(其中
..
表示前面的表达式):

调用一次
paste0()
,将strsplit()生成的输出向量作为参数传递。这会对所有向量进行一种元素级粘贴,因此对于每个唯一的id,最终会得到一个这样的向量:

 [1] "1.." "11." "..." "..." "..." ".22" "..." "..." "..." "..3" "..." "..." "..." "..." "..." "..." "..." "..." "..." "..."
 [1] "1"  "11" ""   ""   ""   "22" ""   ""   ""   "3"  ""   ""   ""   ""   ""   ""   ""   ""   ""   ""
上面的
paste0()
调用包含在以下内容中:

gsub('\\.','',...)
substr(...,1,1)
gsub('^$','.',...)
从所有元素中去除所有文字点,对于每个唯一id,结果如下:

 [1] "1.." "11." "..." "..." "..." ".22" "..." "..." "..." "..3" "..." "..." "..." "..." "..." "..." "..." "..." "..." "..."
 [1] "1"  "11" ""   ""   ""   "22" ""   ""   ""   "3"  ""   ""   ""   ""   ""   ""   ""   ""   ""   ""
上面的
gsub()
调用包含在以下内容中:

gsub('\\.','',...)
substr(...,1,1)
gsub('^$','.',...)
它只提取每个元素的第一个字符,如果它存在,则是该位置所需的字符。空元素是可以接受的,因为这只是意味着id在该位置的任何输入字符串中都没有非点字符

上述
substr()
调用包含在以下内容中:

gsub('\\.','',...)
substr(...,1,1)
gsub('^$','.',...)
这只是将空元素替换为文字点,这显然是在我们将字符串重新组合在一起之前所必需的。对于id==2,我们有:

[[1]]
 [1] "1" "1" "." "." "." "." "." "." "." "." "." "." "." "." "." "." "." "." "." "."

[[2]]
 [1] "." "1" "." "." "." "2" "." "." "." "." "." "." "." "." "." "." "." "." "." "."

[[3]]
 [1] "." "." "." "." "." "2" "." "." "." "3" "." "." "." "." "." "." "." "." "." "."
 [1] "1" "1" "." "." "." "2" "." "." "." "3" "." "." "." "." "." "." "." "." "." "."
这就完成了赋予
lappy()
调用的函数。因此,从该调用中产生的将是表示所需输出字符串的字符向量的
列表。剩下的就是将这些向量的元素折叠成一个字符串,这就是为什么我们需要这样:

sapply(..., function(x) paste0(x,collapse='') )
使用
sapply()

[1] "11...2...3.........." "...................." "......2.....2...4..." ".1...2....3..34....." "....1.....12....3..." "..................44" ".2.......2.........." "...2...2.....2...2.."
因此,剩下的就是生成完整的输出data.frame,类似于输入data.frame:

data.frame(id=unique(my.data$id), my.string=..., stringsAsFactors=F )
导致:

  id            my.string
1  2 11...2...3..........
2  5 ....................
3  6 ......2.....2...4...
4  7 .1...2....3..34.....
5  8 ....1.....12....3...
6  9 ..................44
7 10 .2.......2..........
8 11 ...2...2.....2...2..

我们完了

这里可以使用
stringi
dplyr
包中的函数:

library(stringi)
library(dplyr)

# split my.string
m <- stri_split_boundaries(my.data$my.string, type = "character", simplify = TRUE)

df <- data.frame(id = my.data$id, m)

# function to apply to each column - select "." or unique "number"
myfun <- function(x) if(all(x == ".")) "." else unique(x[x != "."])


df %>%
  # for each id...
  group_by(id) %>%

  # ...and each column, apply function
  summarise_each(funs(myfun)) %>%

  # for each row...
  rowwise() %>%

 #...concatenate strings 
  do(data.frame(id = .[1], mystring = paste(.[-1], collapse = "")))

#   id             mystring
# 1  2 11...2...3..........
# 2  5 ....................
# 3  6 ......2.....2...4...
# 4  7 .1...2....3..34.....
# 5  8 ....1.....12....3...
# 6  9 ..................44
# 7 10 .2.......2..........
# 8 11 ...2...2.....2...2..
库(stringi)
图书馆(dplyr)
#分开我的绳子
m%
#对于每一行。。。
行()
#…连接字符串
do(data.frame(id=[1],mystring=paste([1],collapse=”“))
#id mystring
# 1  2 11...2...3..........
# 2  5 ....................
# 3  6 ......2.....2...4...
# 4  7 .1...2....3..34.....
# 5  8 ....1.....12....3...
# 6  9 ..................44
# 7 10 .2.......2..........
# 8 11 ...2...2.....2...2..

<>代码>因为这个代码正在工作,你可能想考虑把这个移到我试图更清楚地理解这一点,如果你的合并,你的第二行的“<代码> 1”/代码>消失在哪里?@ HWND每一行同一个ID都有一个共同的元素。我会把它添加到帖子中。@JasonAizkalns谢谢。我从来没有张贴任何东西,但我确实考虑到它在目前的情况下。我只是在想,也许在R中有一个1行、2行或3行的解决方案,也许有人可以在这里快速发布。我不知道Code Review站点上是否有很多R程序员。@MarkMiller如果代码按预期工作,并且您希望对其进行改进,那么codereview.stackexchange.com将非常适合您的问题。谢谢Mark!我补充了一个解释,如果你有任何问题,请告诉我。