For example, the words "stack", I want to get an array like:
['s', 'st', 'sta', ... 'stack', 't', 'ta', ... , 'c', 'ck', 'k']
I did this by such code:
def split_word(str)
result = []
chas = str.split("")
len = chas.size
(0..len-1).each do |i|
(i..len-1).each do |j|
result.push(chas[i..j].join)
end
end
result.uniq
end
Is there better and clean way to do that? Thanks.
Use the Split method when the substrings you want are separated by a known delimiting character (or characters). Regular expressions are useful when the string conforms to a fixed pattern. Use the IndexOf and Substring methods in conjunction when you don't want to extract all of the substrings in a string.
I'd write:
def split_word(s)
0.upto(s.length - 1).flat_map do |start|
1.upto(s.length - start).map do |length|
s[start, length]
end
end.uniq
end
groups = split_word("stack")
# ["s", "st", "sta", "stac", "stack", "t", "ta", "tac", "tack", "a", "ac", "ack", "c", "ck", "k"]
It's usually more clear and more compact to use map
(functional) instead of the pattern init empty + each + append + return (imperative).
def substrings(str)
output = []
(0...str.length).each do |i|
(i...str.length).each do |j|
output << str[i..j]
end
end
output
end
this is just a cleaned up version of your method and it works with less steps =)
def split_word s
(0..s.length).inject([]){|ai,i|
(1..s.length - i).inject(ai){|aj,j|
aj << s[i,j]
}
}.uniq
end
And you can also consider using Set
instead of Array for the result.
PS: Here's another idea, based on array product:
def split_word s
indices = (0...s.length).to_a
indices.product(indices).reject{|i,j| i > j}.map{|i,j| s[i..j]}.uniq
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With