Reputation: 464
I have an array:
dictionary = [
'abnormal',
'arm-wrestling',
'absolute',
'airplane',
'airport',
'amazing',
'apple',
'ball'
]
How can I search the first five matches, or less if there are not five matches, by their first letters?
input = "a"
match = dictionary.select { |a| a.match(input) }
puts match
match
returns
["abnormal", "arm-wrestling", "absolute", "airplane", "airport", "amazing", "apple", "ball"]
but I need it to return
["abnormal", "arm-wrestling", "absolute", "airplane", "airport"]
and do not return words like ["ball"]
just because it contains "a".
Upvotes: 2
Views: 2663
Reputation: 52357
If I understood you correctly, you need first five words that starts with 'a'
.
You can use String#start_with?
:
dictionary.select { |word| word.start_with?('a') }.first(5)
For better performance you can lazy
select these five words. It will especially make sense if the collection you are performing search on is growing bigger:
dictionary.lazy.select { |word| word.start_with?('a') }.first(5)
For case insensitive selection:
dictionary.lazy.select { |word| word.start_with?('a', 'A') }.first(5)
Upvotes: 7
Reputation: 160551
Looks like there are lots of answers being tossed out with no regard to processing speed. This doesn't attempt to measure returning the first five words, only determining whether words begin with an 'a'
:
words = %w[
aback
agonizing
bell
bubble
dear
lackadaisical
mouth
nonstop
rinse
steel
stroke
]
var = 'a'
require 'fruity'
This compares all:
var = 'a'
compare do
starts_with { words.select { |w| w.start_with?('a') } }
downcase { words.select { |w| w.downcase.start_with?('a') } }
regexp { words.select { |w| w[0] =~ /a/i } }
mudasobwa1 { words.select { |a| %w|a A|.include? a[0] } }
mudasobwa2 { words.group_by { |w| w[0] }['a'] }
mudasobwa3 { words.grep(/\Aa/).to_a }
mudasobwa4 { words.lazy.grep(/\Aa/).to_a }
stefan { words.select { |word| word.start_with?('a', 'A') } }
andrey_deinko { words.select { |a| a[0] =~ /#{var}/ }}
andrey_deinko2 { words.lazy.select { |word| word.start_with?('a') }.to_a }
end
# >> Running each test 2048 times. Test will take about 4 seconds.
# >> starts_with is similar to stefan
# >> stefan is similar to downcase
# >> downcase is faster than mudasobwa1 by 2x ± 0.1
# >> mudasobwa1 is similar to mudasobwa3
# >> mudasobwa3 is similar to regexp
# >> regexp is similar to mudasobwa2
# >> mudasobwa2 is similar to andrey_deinko2
# >> andrey_deinko2 is similar to mudasobwa4
# >> mudasobwa4 is faster than andrey_deinko by 4x ± 1.0
To try to help the lazy
methods, I expanded the size of the words
array by 1000:
words = (%w[
aback
agonizing
bell
bubble
dear
lackadaisical
mouth
nonstop
rinse
steel
stroke
] * 1000).shuffle
Rerunning shows:
# >> Running each test 2 times. Test will take about 4 seconds.
# >> starts_with is similar to stefan
# >> stefan is similar to andrey_deinko2
# >> andrey_deinko2 is similar to downcase
# >> downcase is similar to mudasobwa2
# >> mudasobwa2 is similar to mudasobwa1
# >> mudasobwa1 is similar to mudasobwa3
# >> mudasobwa3 is similar to mudasobwa4
# >> mudasobwa4 is similar to regexp
# >> regexp is faster than andrey_deinko by 9x ± 1.0
There's a serious speed price to pay with regex so learn to use anchors. I won't go into it here but there are questions and answers on SO showing the differences so search for them.
Keep it simple. Take advantage of the built-in methods designed for the purpose.
Upvotes: 1
Reputation: 121000
▶ dictionary.group_by { |w| w[0] }
#⇒ {
# "a" => [
# [0] "abnormal",
# [1] "arm-wrestling",
# [2] "absolute",
# [3] "airplane",
# [4] "airport",
# [5] "amazing",
# [6] "apple"
# ],
# "b" => [
# [0] "ball"
# ]
# }
dictionary.group_by { |w| w[0] }['a'].take(5)
will return the array requested.
or, using grep
:
dictionary.grep(/\Aa/).take(5)
or, lazy:
dictionary.lazy.grep(/\Aa/).first(5)
Upvotes: 3