Удалить элементы массива, присутствующие в другом массиве
есть список слов и список запрещенных слов. Я хочу просмотреть список слов и отредактировать все запрещенные слова. Это то, что я закончил делать (обратите внимание на catched
boolean):
puts "Give input text:"
text = gets.chomp
puts "Give redacted word:"
redacted = gets.chomp
words = text.split(" ")
redacted = redacted.split(" ")
catched = false
words.each do |word|
redacted.each do |redacted_word|
if word == redacted_word
catched = true
print "REDACTED "
break
end
end
if catched == true
catched = false
else
print word + " "
end
end
есть ли какой-либо правильный/эффективный способ?
3 ответов
можно использовать .reject
чтобы исключить все запрещенные слова, которые присутствуют в redacted
время:
words.reject {|w| redacted.include? w}
если вы хотите получить список запрещенных слов, которые присутствуют в words
массив, вы можете использовать .select
:
words.select {|w| redacted.include? w}
Он также может работать.
words - redacted
+
, -
, &
, эти методы очень просты и полезны.
irb(main):016:0> words = ["a", "b", "a", "c"]
=> ["a", "b", "a", "c"]
irb(main):017:0> redacted = ["a", "b"]
=> ["a", "b"]
irb(main):018:0> words - redacted
=> ["c"]
irb(main):019:0> words + redacted
=> ["a", "b", "a", "c", "a", "b"]
irb(main):020:0> words & redacted
=> ["a", "b"]
это может быть немного более "элегантный". Будет ли это более или менее эффективным, чем ваше решение, я не знаю.
puts "Give input text:"
original_text = gets.chomp
puts "Give redacted word:"
redacted = gets.chomp
redacted_words = redacted.split
print(
redacted_words.inject(original_text) do |text, redacted_word|
text.gsub(/\b#{redacted_word}\b/, 'REDACTED')
end
)
так, что здесь происходит?
- я использую
String#split
без аргументов, потому что' '
по умолчанию, все равно. - С
Array#inject
, следующий блок (глядя наdo
и заканчиваяend
выполняется для каждого элемента массива-в этом случае наш список запрещенных слова.- в каждом раунде вторым аргументом блока будет соответствующий элемент из массива
- первым аргументом блока будет возвращаемое значение блока из предыдущего раунда. Для первого раунда аргумент функции inject (в нашем случае
original_text
) будет использоваться. - возвращаемое значение блока из последнего раунда будет использоваться в качестве возвращаемого значения функции inject.
- в блоке, я замените все вхождения текущего обработанного отредактированного слова в тексте.
-
String#gsub
выполняет gлобальные substitution - в качестве шаблона для замены я использую литерал regexp (
/.../
). Кроме того, это не совсем литерал, поскольку я выполняю подстановку строки (#{...}
) на нем, чтобы получить в настоящее время обработанное отредактированное слово. - в регулярном выражении я окружаю слово, которое нужно отредактировать с
\b
слово граничный matchers. Они соответствуют границе между буквенно-цифровыми и не буквенно-цифровыми символами (или vice verca), не совпадая ни с одним из символов. (Они соответствуют нулевой "позиции" между символами.) Если строка начинается или заканчивается с символов\b
также будет соответствовать началу или концу строки, соответственно, так что мы можем использовать его для сопоставления целых слов.
-
- результат
inject
(что является результатом последнего выполнения блока, т. е. текста, когда все замены имели место) передается в качестве аргументаprint
, который выведет теперь отредактированный текст.
Примечание что, кроме вашего решения, мое не будет рассматривать пунктуацию как части соседних слов.
и Примечание что мое решение будет уязвимо для инъекции regex.
пример 1:
Give input text:
A fnord is a fnord.
Give redacted word:
ford fnord foo
мой вывод:
A REDACTED is a REDACTED.
выход:
A REDACTED is a fnord.
Пример 2:
Give input text:
A fnord is a fnord.
Give redacted word:
fnord.
мой вывод:
A REDACTEDis a fnord.
(обратите внимание, как .
было истолковано как любой символ.)
выход:
A fnord is a REDACTED.