【问题标题】:How can I delete one element from an array by value如何按值从数组中删除一个元素
【发布时间】:2012-04-19 13:14:26
【问题描述】:

我在 Ruby 中有一个元素数组

[2,4,6,3,8]

例如,我需要删除值为 3 的元素

我该怎么做?

【问题讨论】:

  • 我想知道为什么 delete array.delete(3) 在 ruby​​ on rails 控制器中不起作用
  • 可能是由于active record方法delete
  • 问题的标题和正文是矛盾的。正如标题所暗示的那样,您的目标是删除一个具有给定值的元素吗?或者,正如正文所暗示的那样,您的目标是删除具有给定值的所有元素?这两个目标是互斥的;每个人都有不同的解决方案。

标签: arrays ruby


【解决方案1】:

我喜欢其他答案中提到的-=[4]方式删除值为4的元素。

但是有这种方式:

[2,4,6,3,8,6].delete_if { |i| i == 6 }
=> [2, 4, 3, 8]

在“Basic Array Operations”中某处提到了map 函数。

【讨论】:

  • 但是你不能只使用.delete(6)
  • @Zac 当然,但这个答案已经被提及(就像非常简洁的 -= 方式 a-=[4]a=a-[4] . [3,4]-[4],我说我喜欢),但我想提一下另一种可能的方式。
  • 这个方法还有一个好处就是返回数组而不是被删除的元素。
【解决方案2】:

我想我已经明白了:

a = [3, 2, 4, 6, 3, 8]
a.delete(3)
#=> 3
a
#=> [2, 4, 6, 8]

【讨论】:

  • 我个人喜欢[1, 2, 3, 4, 5] - [3],这导致=> [1, 2, 4, 5] 来自irb
  • 如果有多个 3 条目,而我们只想删除其中一个呢? (这是相关的,所以在这里问这个可能是最好的)
  • 请注意,.delete() 将返回删除的值,而不是删除值的修改后的数组。
  • 另一个需要考虑的后果是delete 改变了底层数组,而- 创建了一个没有删除值的新数组(返回给您)。根据您的用例,任何一种方法都可能有意义。
  • @user3721428,delete(3) 不引用位置 3 的元素,而是删除与整数 3 匹配的任何元素。它将删除所有出现的 3,并且与数组索引无关或位置。
【解决方案3】:

在 ruby​​ 中编译所有不同的删除选项

delete - 按值删除匹配的元素。如果多个值匹配,它将全部删除。如果你不关心出现的次数或者确定单次出现,就用这个方法吧。

a = [2, 6, 3, 5, 3, 7]
a.delete(3)  # returns 3
puts a       # return [2, 6, 5, 7]

delete_at - 删除给定索引处的元素。如果您知道索引,请使用此方法。

# continuing from the above example
a.delete_at(2) # returns 5
puts a         # returns [2, 6, 7]

delete_if - 删除所有块为真的元素。这将修改数组。调用块时,数组会立即更改。

b = [1, 2, 5, 4, 9, 10, 11]
b.delete_if {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

reject - 这将返回新数组,其中包含给定块为假的元素。以此保持顺序。

c = [1, 2, 5, 4, 9, 10, 11]
c.reject {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

reject! - 与 delete_if 相同。调用块时,数组可能不会立即更改。

如果你想从数组中删除多个值,最好的选择如下。

a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b    # a - [2, 3, 4, 6, 13]

【讨论】:

    【解决方案4】:

    如果你还想让这个删除操作可以链接,那么你可以删除一些项目并继续对结果数组进行链接操作,使用tap

    [2, 4, 6, 3, 8].tap { |ary| ary.delete(3) }.count #=> 4
    

    【讨论】:

      【解决方案5】:

      第一次出现的无损删除:

      a = [2, 4, 6, 3, 8]
      n = a.index 3
      a.take(n)+a.drop(n+1)
      

      【讨论】:

        【解决方案6】:

        我不确定是否有人说过这一点,但 Array.delete() 和 -= value 将删除数组中传递给它的值的每个实例。为了删除特定元素的第一个实例,您可以执行类似的操作

        arr = [1,3,2,44,5]
        arr.delete_at(arr.index(44))
        
        #=> [1,3,2,5]
        

        可能有更简单的方法。我并不是说这是最佳做法,但这是应该得到认可的。

        【讨论】:

        • 我正在寻找一种方法来做到这一点,并且只删除重复元素的一个实例,这很好用!
        • 我认为这个答案是错误的,仅仅是因为 arr.index() 可以去nil
        【解决方案7】:

        假设您要在数组中的多个位置按值删除 3, 我认为完成这项任务的 ruby​​ 方法是使用 delete_if 方法:

        [2,4,6,3,8,3].delete_if {|x| x == 3 } 
        

        你也可以在'array of arrays'场景中使用delete_if删除元素。

        希望这能解决您的问题

        【讨论】:

          【解决方案8】:

          因此,当您多次出现 3 并且只想删除第一次出现的 3 时,您可以简单地执行以下操作。

          arr = [2, 4, 6, 3, 8, 10, 3, 12]
          
          arr.delete_at arr.index 3
          
          #This will modify arr as [2, 4, 6, 8, 10, 3, 12] where first occurrence of 3 is deleted. Returns the element deleted. In this case => 3.
          

          【讨论】:

            【解决方案9】:

            以下是一些基准:

            require 'fruity'
            
            
            class Array          
              def rodrigo_except(*values)
                self - values
              end    
            
              def niels_except value
                value = value.kind_of?(Array) ? value : [value]
                self - value
              end
            end
            
            ARY = [2,4,6,3,8]
            
            compare do
              soziev  { a = ARY.dup; a.delete(3);               a }
              steve   { a = ARY.dup; a -= [3];                  a }
              barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
              rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
              niels   { a = ARY.dup; a.niels_except(3);           }
            end
            
            # >> Running each test 4096 times. Test will take about 2 seconds.
            # >> soziev is similar to barlop
            # >> barlop is faster than steve by 2x ± 1.0
            # >> steve is faster than rodrigo by 4x ± 1.0
            # >> rodrigo is similar to niels
            

            再次使用包含大量重复项的更大数组:

            class Array          
              def rodrigo_except(*values)
                self - values
              end    
            
              def niels_except value
                value = value.kind_of?(Array) ? value : [value]
                self - value
              end
            end
            
            ARY = [2,4,6,3,8] * 1000
            
            compare do
              soziev  { a = ARY.dup; a.delete(3);               a }
              steve   { a = ARY.dup; a -= [3];                  a }
              barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
              rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
              niels   { a = ARY.dup; a.niels_except(3);           }
            end
            
            # >> Running each test 16 times. Test will take about 1 second.
            # >> steve is faster than soziev by 30.000000000000004% ± 10.0%
            # >> soziev is faster than barlop by 50.0% ± 10.0%
            # >> barlop is faster than rodrigo by 3x ± 0.1
            # >> rodrigo is similar to niels
            

            甚至更大,重复次数更多:

            class Array          
              def rodrigo_except(*values)
                self - values
              end    
            
              def niels_except value
                value = value.kind_of?(Array) ? value : [value]
                self - value
              end
            end
            
            ARY = [2,4,6,3,8] * 100_000
            
            compare do
              soziev  { a = ARY.dup; a.delete(3);               a }
              steve   { a = ARY.dup; a -= [3];                  a }
              barlop  { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
              rodrigo { a = ARY.dup; a.rodrigo_except(3);         }
              niels   { a = ARY.dup; a.niels_except(3);           }
            end
            
            # >> Running each test once. Test will take about 6 seconds.
            # >> steve is similar to soziev
            # >> soziev is faster than barlop by 2x ± 0.1
            # >> barlop is faster than niels by 3x ± 1.0
            # >> niels is similar to rodrigo
            

            【讨论】:

            • 那么,什么是最好的? :)
            【解决方案10】:

            您也可以对其进行修补。我一直不明白为什么 Ruby 对 Hash 有一个 except 方法,但对 Array 没有:

            class Array
              def except value
                value = value.kind_of(Array) ? value : [value]
                self - value
              end
            end
            

            现在你可以这样做了:

            [1,3,7,"436",354,nil].except(354) #=> [1,3,7,"436",nil]
            

            或者:

            [1,3,7,"436",354,nil].except([354, 1]) #=> [3,7,"436",nil]
            

            【讨论】:

            • 您不需要value.kind_of(Array) 测试。只需使用self - Array(value)
            【解决方案11】:

            你可以简单地运行:

            [2,4,6,3,8].delete(3)
            

            【讨论】:

              【解决方案12】:

              我改进了 Niels 的解决方案

              class Array          
                def except(*values)
                  self - values
                end    
              end
              

              现在你可以使用

              [1, 2, 3, 4].except(3, 4) # return [1, 2]
              [1, 2, 3, 4].except(4)    # return [1, 2, 3]
              

              【讨论】:

              • 您的解决方案无法在 irb 控制台上运行 2.2.1 :007 > [1, 2, 3, 4].except(3, 4) NoMethodError: undefined method except for [1, 2, 3, 4]:Array from (irb):7 from /usr/share/rvm/rubies/ruby-2.2.1/bin/irb:11:in <main>
              • 要在IRB中声明,需要将方法添加到Array class Array; def except(*values); self - values; end; end
              【解决方案13】:

              借用 cmets 中的 Travis,这是一个更好的答案:

              我个人喜欢[1, 2, 7, 4, 5] - [7],这导致=> [1, 2, 4, 5] 来自irb

              我修改了他的答案,发现 3 是他的示例数组中的第三个元素。对于那些没有意识到 3 在数组中的位置 2 的人来说,这可能会导致一些混乱。

              【讨论】:

              • 正如 srt32 在答案中指出的那样,使用 .delete- 之间有一个重要的区别。 .delete 将返回从数组中删除的值,如果有的话; - 不会。所以[ 1, 2, 3 ] - [ 2 ] 将返回[ 1, 3 ],而[ 1, 2, 3 ].delete( 2 ) 将返回2
              • array - subArray 不适用于 Array of Arrays,但 array.delete(subArray) 可以。
              • [1,2,3] - [2][1,2,3].delete(2) 之间非常重要的区别在于delete 方法修改了原始数组,而[1,2,3] - [3] 创建了一个新数组.
              • 重新子数组(@Sachin 上面的评论)“当然可以”,你只需要正确的符号:[1,2,[2],2,3,4] - [2] 给你[1, [2], 3, 4],但[1,2,[2],2,3,4] - [[2]] 给你[1, 2, 2, 3, 4]。 :-)
              【解决方案14】:

              .delete_at(3)3 是这个位置。

              【讨论】:

                【解决方案15】:

                另一种选择:

                a = [2,4,6,3,8]
                
                a -= [3]
                

                导致

                => [2, 4, 6, 8] 
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2012-06-19
                  • 1970-01-01
                  • 2010-10-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-05-29
                  相关资源
                  最近更新 更多