Ответ 1
s = "a#asg#sdfg#d##"
a = (0 ... s.length).find_all { |i| s[i,1] == '#' }
Я пытаюсь вернуть индекс ко всем вхождениям определенного символа в строке с использованием Ruby. Строка примера "a#asg#sdfg#d##"
и ожидаемый возврат [1,5,10,12,13]
при поиске символов #
. Следующий код выполняет эту работу, но должен быть более простой способ сделать это?
def occurances (line)
index = 0
all_index = []
line.each_byte do |x|
if x == '#'[0] then
all_index << index
end
index += 1
end
all_index
end
s = "a#asg#sdfg#d##"
a = (0 ... s.length).find_all { |i| s[i,1] == '#' }
require 'enumerator' # Needed in 1.8.6 only
"1#3#a#".enum_for(:scan,/#/).map { Regexp.last_match.begin(0) }
#=> [1, 3, 5]
ETA: Это работает, создавая Enumerator, который использует scan(/#/)
как свой каждый метод.
дает каждое появление указанного шаблона (в данном случае /#/
), а внутри блока вы можете вызвать Regexp.last_match для доступа к объекту MatchData для соответствия.
MatchData#begin(0)
возвращает индекс, где начинается совпадение, и поскольку мы использовали карту в перечислителе, мы возвращаем массив этих индексов.
Здесь менее привлекательный способ:
i = -1
all = []
while i = x.index('#',i+1)
all << i
end
all
В тесте быстрой скорости это было примерно в 3,3 раза быстрее, чем метод FM find_all, и примерно в 2,5 раза быстрее, чем метод sepp2k enum_for.
Здесь длинная цепочка методов:
"a#asg#sdfg#d##".
each_char.
each_with_index.
inject([]) do |indices, (char, idx)|
indices << idx if char == "#"
indices
end
# => [1, 5, 10, 12, 13]
требуется 1.8.7 +
Другое решение, полученное из ответа FM:
s = "a#asg#sdfg#d##"
q = []
s.length.times {|i| q << i if s[i,1] == '#'}
Мне нравится, что Ruby никогда не имеет только одного способа сделать что-то!