【问题标题】:Matching numbers by their order when in two different vectors在两个不同的向量中按顺序匹配数字
【发布时间】:2014-10-31 01:12:39
【问题描述】:

标题并没有真正解决这个问题,但我想不出任何其他方式来表达这个问题。我可以用一个例子来最好地解释这个问题。

假设我们有两个数字向量(每个向量总是升序且唯一):

vector1 <- c(1,3,10,11,24,26,30,31)
vector2 <- c(5,9,15,19,21,23,28,35)

我要做的是创建一个函数,该函数将采用这两个向量并按以下方式匹配它们:

1) 从vector1的第一个元素开始(在本例中为1)

2) 转到vector2并将#1中的元素与vector 2中大于它的第一个元素(在本例中为5)匹配

3) 回到vector1并跳过所有小于我们找到的#2中的值的元素(在这种情况下,我们跳过3,并抓取10)

4) 回到vector2并跳过所有小于我们找到的#3中的值的元素(在这种情况下,我们跳过9并抓取15)

5) 重复直到我们完成所有元素。

我们应该得到的两个向量是:

result1 = c(1,10,24,30)
result2 = c(5,15,28,35)

我目前的解决方案是这样的,但我认为它可能非常低效:

# establishes where we start from the vector2 numbers
# just in case we have vector1 <- c(5,8,10)
# and vector2 <- c(1,2,3,4,6,7). We would want to skip the 1,2,3,4 values

  i <- 1
  while(vector2[i]<vector1[1]){
    i <- i+1
  }

# starts the result1 vector with the first value from the vector1

  result1 <- vector1[1]

# starts the result2 vector empty and will add as we loop through

  result2 <- c()


# super complicated and probably hugely inefficient loop within a loop within a loop 
# i really want to avoid doing this, but I cannot think of any other way to accomplish this

  for(j in 1:length(vector1)){

    while(vector1[j] > vector2[i] && (i+1) <= length(vector2)){

      result1 <- c(result1,vector1[j])
      result2 <- c(result2,vector2[i])         

      while(vector1[j] > vector2[i+1] && (i+2) <= length(vector2)){

        i <- i+1
      }
      i <- i+1
    }
  }

  ## have to add on the last vector2 value cause while loop skips it
  ## if it doesn't exist (there are no more vector2 values bigger) we put in an NA

  if(result1[length(result1)] < vector2[i]){
    result2 <- c(result2,vector2[i])
  }
  else{
    ### we ran out of vector2 values that are bigger 
    result2 <- c(result2,NA)
  }

【问题讨论】:

    标签: r loops


    【解决方案1】:

    这真的很难解释。就叫它魔法吧:)

    vector1 <- c(1,3,10,11,24,26,30,31)
    vector2 <- c(5,9,15,19,21,23,28,35)
    ## another case
    # vector2 <- c(0,9,15,19,21,23,28,35)
    
    ## handling the case where vector2 min value(s) are < vector1 min value
    if (any(idx <- which(min(vector1) >= vector2))) 
       vector2 <- vector2[-idx]
    
    ## interleave the two vectors
    tmp <- c(vector1,vector2)[order(c(order(vector1), order(vector2)))]
    
    ## if we sort the vectors, which pairwise elements are from the same vector
    r <- rle(sort(tmp) %in% vector1)$lengths
    
    ## I want to "remove" all the pairwise elements which are from the same vector
    ## so I again interleave two vectors:
    ## the first will be all TRUEs because I want the first instance of each *new* vector
    ## the second will be all FALSEs identifying the elements I want to throw out because
    ## there is a sequence of elements from the same vector
    l <- rep(1, length(r))
    ord <- c(l, r - 1)[order(c(order(r), order(l)))]
    
    ## create some dummy TRUE/FALSE to identify the ones I want
    res <- sort(tmp)[unlist(Map(rep, c(TRUE, FALSE), ord))]
    
    setNames(split(res, res %in% vector2), c('result1', 'result2'))
    
    # $result1
    # [1]  1 10 24 30
    # 
    # $result2
    # [1]  5 15 28 35
    

    显然,这仅在您所说的两个向量都是升序且唯一的情况下才有效

    编辑:

    适用于重复项:

    vector1 <- c(1,3,10,11,24,26,30,31)
    vector2 <- c(5,9,15,19,21,23,28,35)
    vector2 <- c(0,9,15,19,21,23,28,35)
    vector2 <- c(1,3,3,5,7,9,28,35)
    
    f <- function(v1, v2) {
      if (any(idx <- which(min(vector1) >= vector2))) 
        vector2 <- vector2[-idx]
    
      vector1 <- paste0(vector1, '.0')
      vector2 <- paste0(vector2, '.00')
    
      n <- function(x) as.numeric(x)
    
      tmp <- c(vector1, vector2)[order(n(c(vector1, vector2)))]
    
      m <- tmp[1]
      idx <- c(TRUE, sapply(1:(length(tmp) - 1), function(x) {
        if (n(tmp[x + 1]) > n(m)) {
          if (gsub('^.*\\.','', tmp[x + 1]) == gsub('^.*\\.','', m)) 
            FALSE
          else {
            m <<- tmp[x + 1]
            TRUE
          }
        } else FALSE
      }))
    
      setNames(split(n(tmp[idx]), grepl('\\.00$', tmp[idx])), c('result1','result2'))
    }
    f(vector1, vector2)
    
    # $result1
    # [1]  1 10 30
    # 
    # $result2
    # [1]  3 28 35
    

    【讨论】:

    • 这是一个非常聪明的解决方案。我从没想过交错这两个向量(我想我没有充分利用我的上升和唯一性假设)。我刚刚更改了最后一行代码并让它工作。非常感谢!
    • 很抱歉打扰了,但在尝试将其与我之前的解决方案进行比较时,我注意到了一个错误。如果 vector1 值开始于 vector2 值之上,则输出不正确。例如,vector1 = (3,10,...) 和 vector2 是 (1,5,9...) 我通过简单地调整 vector2 以删除任何低于 vector1 初始值的值来解决这个问题
    • 你可以只使用vector2作为vector 1,反之亦然吗?也就是说,总是先使用第一个元素最小的向量?
    • 是的,这也应该有效! Vector1 在我的代码中应用这个想法虽然具有特定的含义,所以我试图以特定的方式对它们进行排序。但仅就这个问题而言,这可能是一个更好的解决方案
    • 也许添加这一行将适用于这种情况if (any(idx &lt;- which(min(vector1) &gt;= vector2))) vector2 &lt;- vector2[-idx] 见编辑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-03
    • 2014-10-24
    • 2020-12-27
    • 1970-01-01
    相关资源
    最近更新 更多