R编程:创建成对元素的列表

时间:2022-09-13 13:30:33

I have a list of elements say:

我有一个元素列表:

l <- c("x","ya1","xb3","yb3","ab","xc3","y","xa1","yd4")

Out of this list I would like to make a list of the matching x,y pairs, i.e.

在这个列表中,我想列出一个匹配的x,y对的列表。

(("xa1" "ya1") ("xb3" "yb3") ("x" "y"))

In essence, I need to capture the X elements, the Y elements and then pair them up: I know how to do the X,Y extraction part:

本质上,我需要捕捉X元素,Y元素,然后将它们配对:我知道如何做X,Y提取部分:

xelems <- grep("^x", l, perl=TRUE, value=TRUE)
yelems <- grep("^y", l, perl=TRUE, value=TRUE)

An X element pairs up with a Y element when

当X元素与Y元素配对时。

1. xElem == yElem # if xElem and yElem are one char long, i.e. 'x' and 'y'    
2. substr(xElem,1,nchar(xElem)) == substr(yElem,1,nchar(yElem))

There is no order, i.e. matching xElem and yElem can be positioned anywhere.

没有顺序,即匹配的xElem和yElem可以定位在任何地方。

I am however not very sure about the next part. I am more familiar with the SKILL programming language (SKILL is a LISP derivative) and this is how I write it:

但是我对下一部分不是很确定。我更熟悉技能编程语言(技能是LISP的衍生),我是这样写的:

procedure( get_xy_pairs(inputList "l")
  let(( yElem (xyPairs nil) xList yList)
    xList=setof(i inputList rexMatchp("^x" i))
    yList=setof(i inputList rexMatchp("^y" i))
    when(xList && yList
      unless(length(xList)==length(yList)
    warn("xList and yList mismatch : %d vs %d\n" length(xList) length(yList))
      )
      foreach(xElem xList
        if(xElem=="x"
          then yElem="y"
          else yElem=strcat("y" substring(xElem 2 strlen(xElem)))
        )
        if(member(yElem yList)
          then xyPairs=cons(list(xElem yElem) xyPairs)
          else warn("x element %s has no matching y element \n" xElem)
        )
      )
    )
    xyPairs
  )
)

When run on l, this would return

在l上运行时,它会返回

get_xy_pairs(l)
*WARNING* x element xc3 has no matching y element 
(("xa1" "ya1") ("xb3" "yb3") ("x" "y"))

As I am still new to R, I would appreciate if you folks can help. Besides, I do understand the R folks tend to avoid for loops and are more into lapply ?

由于我还是新人,如果你们能帮忙,我将不胜感激。另外,我也知道R族倾向于避免循环,更喜欢lapply吗?

Thx in advance. Riad.

提前谢谢。利雅得。

2 个解决方案

#1


3  

Maybe something like this would work. (Only tested on your sample data.)

也许像这样的东西有用。(只对您的样本数据进行测试。)

## Remove any item not starting with x or y
l2 <- l[grepl("^x|^y", l)]

## Split into a list of items starting with x
##   and items starting with y
L <- split(l2, grepl("^x", l2))

## Give "names" to the "starting with y" group
names(L[[1]]) <- gsub("^y", "x", L[[1]])

## Use match to match the names in the y group with
##   the values from the x group. This results in a
##   nice named vector with the pairs you want
Matches <- L[[1]][match(L[[2]], names(L[[1]]), nomatch=0)]
Matches
#     x   xb3   xa1 
#   "y" "yb3" "ya1" 

As a data.frame:

data.frame:

MatchesDF <- data.frame(x = names(Matches), y = unname(Matches))
MatchesDF
#     x   y
# 1   x   y
# 2 xb3 yb3
# 3 xa1 ya1

#2


1  

I would store tuples in a list, i.e:

我会将元组存储在列表中,即:

xypairs
[[1]]
[1] "x"    "y"

[[2]]
[2] "xb3"  "yb3"

Your procedure can be simplified with match and substring.

您的过程可以使用match和子字符串进行简化。

xends <- substring(xelems, 2)
yends <- substring(yelems, 2)
ypaired <- match(xends, yends)  # Indices of yelems that match xelems

# Now we need to handle the no-matches:
xsorted <- c(xelems, rep(NA, sum(is.na(ypaired))))
ysorted <- yelems[ypaired]
ysorted <- c(ysorted, yelems[!(yelems %in% ysorted)])

# Now we create the list of tuples:
xypairs <- lapply(1:length(ysorted), function(i) {
  c(xsorted[i], ysorted[i])
})

Result:

结果:

xypairs
[[1]]
[1] "x" "y"

[[2]]
[1] "xb3" "yb3"

[[3]]
[1] "xc3" NA   

[[4]]
[1] "xa1" "ya1"

[[5]]
[1] NA    "yd4"

#1


3  

Maybe something like this would work. (Only tested on your sample data.)

也许像这样的东西有用。(只对您的样本数据进行测试。)

## Remove any item not starting with x or y
l2 <- l[grepl("^x|^y", l)]

## Split into a list of items starting with x
##   and items starting with y
L <- split(l2, grepl("^x", l2))

## Give "names" to the "starting with y" group
names(L[[1]]) <- gsub("^y", "x", L[[1]])

## Use match to match the names in the y group with
##   the values from the x group. This results in a
##   nice named vector with the pairs you want
Matches <- L[[1]][match(L[[2]], names(L[[1]]), nomatch=0)]
Matches
#     x   xb3   xa1 
#   "y" "yb3" "ya1" 

As a data.frame:

data.frame:

MatchesDF <- data.frame(x = names(Matches), y = unname(Matches))
MatchesDF
#     x   y
# 1   x   y
# 2 xb3 yb3
# 3 xa1 ya1

#2


1  

I would store tuples in a list, i.e:

我会将元组存储在列表中,即:

xypairs
[[1]]
[1] "x"    "y"

[[2]]
[2] "xb3"  "yb3"

Your procedure can be simplified with match and substring.

您的过程可以使用match和子字符串进行简化。

xends <- substring(xelems, 2)
yends <- substring(yelems, 2)
ypaired <- match(xends, yends)  # Indices of yelems that match xelems

# Now we need to handle the no-matches:
xsorted <- c(xelems, rep(NA, sum(is.na(ypaired))))
ysorted <- yelems[ypaired]
ysorted <- c(ysorted, yelems[!(yelems %in% ysorted)])

# Now we create the list of tuples:
xypairs <- lapply(1:length(ysorted), function(i) {
  c(xsorted[i], ysorted[i])
})

Result:

结果:

xypairs
[[1]]
[1] "x" "y"

[[2]]
[1] "xb3" "yb3"

[[3]]
[1] "xc3" NA   

[[4]]
[1] "xa1" "ya1"

[[5]]
[1] NA    "yd4"