Удалить только определенные дубликаты в массиве с помощью Ruby

Есть ли способ удалить определенные дубликаты в массиве с помощью Ruby? Пример массива:

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

Я хочу удалить только дубликаты "removeme" в этом массиве. Желаемый результат:

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

Есть ли такой метод, чтобы получить желаемый результат? ["hello", "removeme", "removeme", "hello", "testing"].uniq('removeme')

Каков желаемый результат, если бы массив был ["hello", "removeme", "hello", "testing", "removeme"]? Я хочу знать, важен ли выбор сохраняемого элемента (здесь первый или второй экземпляр "removeme").

Cary Swoveland 14.04.2023 05:12

Привет @CarySwoveland, желаемый результат будет ["hello", "removeme", "hello", "testing"], я хочу удалить дубликаты с определенной строкой, например, выше, я хочу сохранить одно значение removeme в массиве. Я не могу использовать uniq, потому что это повлияет на значение hello в массиве

oj5th 14.04.2023 05:31

Вы сказали: «Я хочу сохранить одно значение removeme в массиве», но я спросил, какое из них оставить. Высказывание «желаемый результат будет ["hello", "removeme", "hello", "testing"]» предполагает, что вы хотите сохранить первый экземпляр, но может случиться так, что вам все равно, какой из них будет сохранен. Вам нужно уточнить это. При уточнении вопросов всегда лучше отредактировать свой вопрос, а не уточнять его в комментариях, так как вопросы должны быть отдельными — от читателей не требуется читать все комментарии, чтобы понять вопрос.

Cary Swoveland 14.04.2023 06:29

Это чисто Ruby-проблема, поэтому у вас не должно быть тегов Rails.

Cary Swoveland 14.04.2023 06:50
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
4
4
128
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Можно использовать следующий метод.

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

Как насчет отклонения всего, кроме первого появления слова, как это.

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_index и Array#reject.

Или вы можете повторить массив и скопировать только первое вхождение в новый массив:

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"]

Видеть:

Ответ принят как подходящий

Вы можете использовать uniq с блоком, который удаляет дубликаты на основе возвращаемого значения блока:

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

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

Для элементов, равных '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 нужен, потому что uniq без блока возвращает новый массив вместо перечислителя (который в свою очередь нужен для цепочки with_index).

Умный! Я пытался сделать что-то подобное, но споткнулся на последнем шаге. Я думаю, другой способ был бы n = 0; ary.uniq { |obj| obj.eql?('removeme') || n += 1 }.

Cary Swoveland 15.04.2023 00:23

@CarySwoveland Я добавил ваш подход с индексом элемента.

Stefan 15.04.2023 13:21

Как насчет расширения класса 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"], что дает желаемый результат.

Я голосую против, потому что удаляются первые экземпляры как "hello", так и "removeme", а не только последний, но даже если метод был правильным, нет причин загрязнять класс Array добавлением нового метода.

Cary Swoveland 15.04.2023 22:27

Как известно, в этом вопросе таких условий не было, я предложил другой вариант реализации.

Andrew Zhuk 15.04.2023 23:07

Другие вопросы по теме