【问题标题】:How to remove items in a vector from another vector如何从另一个向量中删除向量中的项目
【发布时间】:2018-03-26 10:12:18
【问题描述】:

我有两个向量:

a = c(1,1,2,2,3,3,4,4) 
b = c(1)

我想从a 中删除b第一个 匹配项。因此,这里只删除了a 中的第一个1

c = c(1,2,2,3,3,4,4)

a 中项目的顺序并不重要。

我试过这段代码:

a[a != b]
a[! a %in% b] 

两个结果都是:

[1] 2 2 3 3 4 4.

所有数字 1 都被删除。但是,我只想从a 中删除b 中的特定项目。

如果b = c(1, 1, 2),那么我希望结果

[1] 2 3 3 4 4

a[-(1:3)]

上面的代码可能会导致[1] 2 3 3 4 4的结果。但是,我希望它可以更灵活。例如,当项目的顺序未知或随机时:

a = c(3,4,3,1,2,2,1,4)

我如何使用 R 来做到这一点?

【问题讨论】:

标签: r


【解决方案1】:

vecsets 包可以执行标准集合操作,同时保留重复:

vecsets::vsetdiff( c(1,1,2,2,3,3,4,4), c(1) )
## [1] 1 2 2 3 3 4 4

vecsets::vsetdiff( c(1,1,2,2,3,3,4,4), c(1,1,2) )
## [1] 2 3 3 4 4

请注意,它将保留第一个参数的顺序。使用你的最后一个例子:

vecsets::vsetdiff( c(3,4,3,1,2,2,1,4), c(1,1,2) )
## [1] 3 4 3 2 4

【讨论】:

    【解决方案2】:

    this answer 中获取灵感到我在评论中链接的一个问题,您可以使用 包中的fsetdiff
    它将all 作为参数,这样可以避免只返回唯一值,就像setdiff 一样:

    library(data.table)
    
    # with your first example (b = c(1)):
    unlist(fsetdiff(data.table(v1=a), data.table(v1=b), all = TRUE))
    # v11 v12 v13 v14 v15 v16 v17 
    #  1   2   2   3   3   4   4
    
    # with second example (b = c(1, 1, 2)):
    unlist(fsetdiff(data.table(v1=a), data.table(v1=b), all = TRUE))
    # v11 v12 v13 v14 v15 
    #  2   3   3   4   4
    

    【讨论】:

      【解决方案3】:

      您可以使用which()

      a = c(3, 4, 3, 1, 2, 2, 1, 4)
      a
      ## [1] 3 4 3 1 2 2 1 4
      
      b = 1
      
      a[- which(a %in% b)[1]]
      ## [1] 3 4 3 2 2 1 4
      

      案例b有两个元素:

      b2 = c(1, 2)
      
      sapply(seq_along(b1), function(x) a <<- a[- which(a == x)[1]])[[2]]
      ## [1] 3 4 3 2 1 4
      

      或者三个...

      b3 <- c(1, 2, 3)
      
      sapply(seq_along(b1), function(x) a <<- a[- which(a == x)[1]])[[3]]
      # [1] 4 3 2 1 4
      

      【讨论】:

      • 再次感谢您的帮助!当 b 的列表包含一个值时,它工作正常。我现在正在尝试一个更复杂的列表。例如,b = c(1,1,2)。
      • @luyan 可能有更好的方法,但简单的for(x in b) a &lt;- a[-which(a == x)[1]] 有效。如果您不想改变它,请在 a 的副本上执行此操作。
      • @luyan 很高兴它可以工作,但在 R 中,我倾向于将任何 for 循环的使用视为想象力的失败。另一方面,如果一个快速而肮脏的循环可以满足您的需求,并且问题规模足够小以至于效率不是问题,那么没有太多理由花费大量时间提出矢量化方法。
      • 回应对一篇现已删除的帖子的评论,该帖子涉及此帖子;像这样的函数的重复迭代感觉就像 R 中的 for 循环实际上是正确的事情。约翰科尔曼的评论的后半部分特别相关。这不是 R 本身擅长的那种操作,所以如果需要更高的效率,那么迁移到 C/C++ 函数可能比尝试重做 *apply 范式更有成效。或许可以看看 Rcpp 包,它使这相对容易。
      • @Aaron 好点。知道 R 中的循环何时合适是我还没有掌握的事情之一。我经常使用它们,但是当我这样做时,我很难摆脱我错过了一个更优雅的解决方案的感觉。我曾多次编写复杂的基于循环的解决方案,但后来却发现了一个 1-liner,它可以更快地完成相同的事情。
      【解决方案4】:

      我不认为以下是最好的解决方案(vecsets 方法让我觉得最好),但@Aaron 关于可能使用 Rcpp 的评论让我觉得很有趣。这是我第一次使用那个包。如果不出意外,我能够在不到 20 分钟的时间内获得工作代码这一事实强调了他的观点,即 Rcpp 使它相对容易:

      library(Rcpp)
      cppFunction('
        NumericVector difference(NumericVector xs, NumericVector ys){
          int m = xs.size();
          int n = ys.size();
          float flag = 1 + abs(max(xs)) + abs(max(ys)); //occurs in neither xs nor ys
          NumericVector zs = clone(xs);
          for(int i = 0; i < n; i++){
            double y = ys[i];
            int j = 0;
            while(j < m && zs[j]!= y) j++;
            if(j < m) zs[j] = flag;
          }
          int count = 0;
          for(int k = 0; k < m; k++){
            if(zs[k] < flag) count++;
          }
          NumericVector ws(count);
          int k = 0;
          for(int j = 0; j < m; j++){
            if(zs[j] < flag){
              ws[k] = zs[j];
              k++;
            }
          }
          return ws;
        }
      ')
      

      在你获得这个之后:

      > a = c(1,1,2,2,3,3,4,4)
      > b = c(1,2,1)
      > difference(a,b)
      [1] 2 3 3 4 4
      

      由于这是我第一次尝试编写此类代码,我确信它可以通过多种方式进行改进。

      【讨论】:

        【解决方案5】:

        语法顺序有点令人沮丧,但 Reducewhich 只使用 Base R。

        Reduce(b, a) a[-which(a==b)[1]], a, b)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-05
          相关资源
          最近更新 更多