使用 Ruby 仅删除数组中的特定重复项

Remove only specific duplicates in array using Ruby

提问人:oj5th 提问时间:4/14/2023 最后编辑:Mark Rotteveeloj5th 更新时间:5/10/2023 访问量:138

问:

有没有办法使用 Ruby 删除数组中的特定重复项?数组示例:

["hello", "removeme", "removeme", "hello", "testing"]

我只想删除该数组上的重复项。所需的输出为:"removeme"

["hello", "removeme", "hello", "testing"]

有没有这样的方法来获得所需的输出?["hello", "removeme", "removeme", "hello", "testing"].uniq('removeme')

数组 Ruby 重复项

评论

1赞 Cary Swoveland 4/14/2023
如果数组是 ?我想知道选择要保留的元素的选择(这里是 的第一个或第二个实例)是否重要。["hello", "removeme", "hello", "testing", "removeme"]"removeme"
0赞 oj5th 4/14/2023
嗨,@CarySwoveland,期望的结果是,我想删除带有特定字符串的重复项,例如上面我想在数组中保留一个值。我不能使用,因为它会影响数组中的值["hello", "removeme", "hello", "testing"]removemeuniqhello
2赞 Cary Swoveland 4/14/2023
你说,“我想在数组中保留一个值”,但我问要保留哪一个。说“期望的结果是”表明您希望保留第一个实例,但可能是您不在乎保留哪个实例。你需要澄清这一点。在澄清问题时,最好编辑您的问题而不是在评论中详细说明,因为问题应该是独立的——不应要求读者阅读所有评论来理解问题。removeme["hello", "removeme", "hello", "testing"]
2赞 Cary Swoveland 4/14/2023
这是一个纯 Ruby 的问题,所以你不应该有 Rails 标签。

答:

3赞 Cary Swoveland 4/14/2023 #1

可以使用以下方法。

def removem(arr, to_remove)
  i = arr.index(to_remove)
  i.nil? ? arr : (arr - [to_remove]).insert(i, to_remove)
end

假设给定的数组如下所示。

arr = ["hello", "removeme", "hello", "goodbye", "removeme", "testing"]

然后

removem(arr, "removeme")
  #=> ["hello", "hello", "goodbye", "testing", "removeme"]
removem(arr, "goodbye")
  #=> ["hello", "removeme", "hello", "goodbye", "removeme", "testing"]
removem(arr, "missing")
  #=> ["hello", "removeme", "hello", "goodbye", "removeme", "testing"]

在每个示例中都保持不变。arr

参见 Array#index 和 Array#insert

4赞 spickermann 4/14/2023 #2

像这样拒绝除第一次出现这个词之外的所有内容怎么样?

def uniq_word(array, word)
  return array unless first = array.index(word)
  array.reject.with_index { |elem, index| index > first && elem == word }
end

array = ["hello", "removeme", "removeme", "hello", "testing"]

uniq_word(array, 'removeme')
#=> ["hello", "removeme", "hello", "testing"]

请参阅 Array#index、Enumerator#with_indexArray#reject

或者,您可以迭代 aray 并仅将第一次出现复制到新数组中:

def uniq_word(array, word)
  found = false

  [].tap do |result|
    array.each do |elem|
      if elem == word && !found
        found = true
        next
      end

      result << elem
    end
  end
end

array = ["hello", "removeme", "removeme", "hello", "testing"]

uniq_word(array, 'removeme')
#=> ["hello", "removeme", "hello", "testing"]

看:

8赞 Stefan 4/14/2023 #3

您可以将 uniq 与块一起使用,该块会根据块的返回值删除重复项:

ary = ["hello", "removeme", "removeme", "hello", "testing"]

ary.uniq { |obj| obj.eql?('removeme') || Object.new }
#=> ["hello", "removeme", "hello", "testing"]

对于等于我们返回的元素,对于其他所有元素(、 和 ),我们返回一个新对象:(注意不同的对象 ID)'removeme'true'hello''hello''testing'

"hello"    → #<Object:0x00007f9ab08590d8>
"removeme" → true
"removeme" → true
"hello"    → #<Object:0x00007f9ab0858d68> 
"testing"  → #<Object:0x00007f9ab08589f8>

所有具有相同返回值的元素都被视为重复元素,即 将被视为副本,而将任何其他内容视为唯一,无论其实际值如何。这允许保留两个相同的字符串。uniq'removeme''hello'

除了 ,您还可以使用元素的索引:Object.new

ary.enum_for(:uniq).with_index { |obj, i| obj.eql?('removeme') || i }
#=> ["hello", "removeme", "hello", "testing"]

enum_for是必需的,因为如果没有块,则返回一个新数组而不是枚举器(而枚举器又需要枚举器来链接with_index)。uniq

评论

2赞 Cary Swoveland 4/15/2023
聪明!我试着做类似的事情,但在最后一步被绊倒了。我想另一种方式是.n = 0; ary.uniq { |obj| obj.eql?('removeme') || n += 1 }
1赞 Stefan 4/15/2023
@CarySwoveland我已经添加了您的方法与元素的索引。
-2赞 Andrew Zhuk 4/16/2023 #4

通过添加新方法来扩展 Array 类怎么样?

class Array
  def uniq_specific!(targets)
    found = {}
    targets.each { |target| found[target] = false }

    delete_if do |item|
      if targets.include?(item)
        if found[item]
          true
        else
          found[item] = true
          false
        end
      else
        false
      end
    end
  end
end

array = ["hello", "removeme", "removeme", "hello", "world", "world", "testing"]
array.uniq_specific!(["removeme", "hello"])

array # => ["removeme", "hello", "world", "world", "testing"]

我们定义了一个新方法uniq_specific!用于接受目标元素数组作为参数的 Array 类。它遍历数组并删除每个目标元素的所有匹配项,但第一个元素除外。然后,我们在目标值为 [“removeme”, “hello”] 的示例数组上调用此方法,从而产生所需的输出。

评论

0赞 Cary Swoveland 4/16/2023
我投了反对票,因为两者的第一个实例都被删除了,而不仅仅是后者,但即使方法是正确的,也没有理由通过添加新方法来污染类。"hello""removeme"Array
0赞 Andrew Zhuk 4/16/2023
如你所知,这个问题没有这样的条件,我提出了另一个实现选项。