Возвращение повторяющихся символов в строке - PullRequest
1 голос
/ 20 апреля 2019

Я учу Руби.Как часть моего HW, я должен найти первое вхождение двух повторяющихся символов в строке в строке и вернуть дублированный символ.Вот что я придумал:

require 'set'

def find_a_dup_using_set(arr)
   s = Set.new
   arr.find { |e| !s.add?(e) }
end
 p find_a_dup_using_set(["q", "q", "c", "d", "e"])

Вопрос: был ли это лучший подход?Возможно, потому что я все еще учусь, но я чувствую, что это не то, о чем они просили, а то, что я знал, что работало на основе исследований, которые я проводил.Есть ли причина не использовать массив для чего-то подобного?

Ответы [ 2 ]

2 голосов
/ 20 апреля 2019

Почему бы просто не использовать простое регулярное выражение?

str = 'abccdd'
str[/(.)\1/][0]
=> 'c'

Здесь регулярное выражение группирует каждый символ и находит первую последовательную пару.Тогда мы просто получаем первый символ, вызывая 0 index.

В ruby ​​есть несколько способов использовать Регулярное выражение для строки.Таким образом, вы могли бы поставить этот метод.

def find_first_dup_in_string(str)
  str[/(.)\1/][0] 
end

Вот вариант ответа Тадмана, и я включу тесты для сравнения ОБНОВЛЕНО, чтобы использовать each_char согласно комментариям.

def find_first_dup_a(str)
  d = ''
  str.each_char.each_cons(2){|c| d = c[0]; break if c[0] == c[1] }
  d
end

alpha=[*'a'..'z']
str = ''
1000.times{ str << alpha.sample}

cycles = 100000

Benchmark.bm do |x|
  x.report(:ruby) {  cycles.times { find_first_dup_a(str) } }
  x.report(:regex) { cycles.times { find_first_dup_in_string(str) } }
end

ruby  0.330000   0.010000   0.340000 (  0.338940)
regex  0.140000   0.000000   0.140000 (  0.151719)
=> [
    [0] #<Benchmark::Tms:0x00007fb6a0bd4c88 @label="ruby", @real=0.33893999992869794, @cstime=0.0, @cutime=0.0, @stime=0.010000000000000009, @utime=0.33000000000000007, @total=0.3400000000000001>,
    [1] #<Benchmark::Tms:0x00007fb6a2601390 @label="regex", @real=0.1517189999576658, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.14000000000000057, @total=0.14000000000000057>
]

И забавное совпадение, не имеющее отношения вообще:)

14.0/33.0 * 100
=> 42.42424242424242
1 голос
/ 21 апреля 2019

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

def duup?(str)
  !!str.chars.each_cons(2).find { |a,b| a == b }
end

Где это просто использует each_cons ( каждый подряд ) итератор и находит первый экземпляр двух букв идентичными.

Если это не достаточно захватывающе:

def duup?(str)
  !!str.chars.each_cons(2).lazy.map(&:uniq).map(&:length).include?(1)
end

Где это сводит каждую пару только к уникальным элементам и ищетте, которые свернуты в массив длины 1. lazy добавлено для хорошей меры.

Вы также можете сделать что-то немного неясное, например:

def duup?(str)
 !!(1...str.length).find { |i| str[i].ord ^ str[i-1].ord == 0 }
end

Если вам нравится двоичная математика, XOR вернет ноль, если два значения идентичны, поскольку они отменяют себя.

Или для простоты:

def duup?(str)
  !!str.chars.each_cons(2).find { |v| v == v.reverse }
end

Где, если обратный набор совпадает с прямым набором, он долженбыть одним и тем же.

Обратите внимание, что некоторые из них можно легко масштабировать до N символов, так как 2 является совершенно произвольным.

В качестве упражненияВы можете хотеть скамейкупометьте эти подпрограммы строками различной длины.Некоторые подходы могут быть нежизнеспособными на огромных строках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...