Вопрос

I'm writing a program to compute the digital root of an input phrase. I have the whole digital root algorithm working, but certain input phrases don't seem to mesh well with the split method. I want to separate the input phrase into an array of "characters", or single character strings.

puts "Please enter a phrase to be converted"
phrase = gets.chomp.downcase!
phrase = phrase.split("")

Whenever the input string does not have any capitalized letters, I get the error undefined method 'split' for nil:NilClass (NoMethodError) . Any ideas? Thanks.

Это было полезно?

Решение

Remove the !

puts "Please enter a phrase to be converted"
phrase = gets.chomp.downcase
phrase = phrase.split("")

By convention, the method with tailing ! means altering the receiver rather than create a new copy. String#downcase! returns nil if no character in the String is downcased.

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

You can do this a few other ways too

puts "Please enter a phrase to be converted"
phrase = gets.chomp.downcase.chars.to_a

OR (Although this will be slower due to the iteration over an array it is still faster than #split)

puts "Please enter a phrase to be converted"
phrase = gets.chomp.chars.map(&:downcase)

@engineersmnky shows two ways to accomplish the same thing, but there is a big difference in the speed between the two:

require 'fruity'

phrase = "Please enter a phrase to be converted"

puts "Running chars.to_a vs. split"
compare {
  chars_to_a1 { phrase.chars.to_a }
  split1 { phrase.split("") }
}

puts '-' * 20

puts "Running downcase.chars.to_a vs. chars.to_a.map(&:downcase)"
compare {
  chars_to_a2 { phrase.chomp.downcase.chars.to_a }
  map_downcase { phrase.chomp.chars.to_a.map(&:downcase) }
}

Running that results in this output on my laptop:

# >> Running chars.to_a vs. split
# >> Running each test 1024 times. Test will take about 1 second.
# >> chars_to_a1 is faster than split1 by 5x ± 0.1

I was surprised that split is that much slower in the first test, but it's hard to argue against the numbers.

Piggybacking on that knowledge, I used the faster result to test the result of downcase on the string, versus against the individual letters.

# >> --------------------
# >> Running downcase.chars.to_a vs. chars.to_a.map(&:downcase)
# >> Running each test 1024 times. Test will take about 1 second.
# >> chars_to_a2 is faster than map_downcase by 2.4x ± 0.1

So, for fastest results use downcase.chars.to_a.


Also would like to point out chars.map(&:downcase) is still faster than downcase.split('')...

Here's the additional benchmark:

compare {
  chars_to_a2 { phrase.chomp.downcase.chars.to_a }
  map_downcase { phrase.chomp.chars.to_a.map(&:downcase) }
  chars_map { phrase.chomp.chars.map(&:downcase) }
}
# >> Running each test 1024 times. Test will take about 1 second.
# >> chars_to_a2 is faster than chars_map by 2.4x ± 0.1
# >> chars_map is similar to map_downcase

phrase.chomp.downcase.chars.to_a still outruns the others by 2x.

It's important to note that using map to downcase the split string is expensive and will become more expensive the longer the source string becomes. Making the initial string 10x longer allows phrase.chomp.downcase.chars.to_a to run 3x faster than the other two.

phrase = "Please enter a phrase to be converted" * 10

compare {
  chars_to_a2 { phrase.chomp.downcase.chars.to_a }
  map_downcase { phrase.chomp.chars.to_a.map(&:downcase) }
  chars_map { phrase.chomp.chars.map(&:downcase) }
}
# >> Running each test 128 times. Test will take about 1 second.
# >> chars_to_a2 is faster than map_downcase by 3.0x ± 0.1
# >> map_downcase is similar to chars_map
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top