What is the best way to split a string to get all Ruby substrings?

For example, the words "stack", I want to get an array like:

['s', 'st', 'sta', ... 'stack', 't', 'ta', ... , 'c', 'ck', 'k'] 

I did this with the following 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 a better and cleaner way to do this? Thanks.

+9
string ruby
source share
7 answers
 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 use Set instead of Array for the result.

PS: Here's another idea based on an 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 
+11
source share

I would 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 is usually more understandable and more compact to use map (functional) instead of the template init empty + each + append + return (imperative).

+5
source share

Do not think so.

Here is my attempt:

 def split_word(str) length = str.length - 1 [].tap do |result| 0.upto(length) do |i| length.downto(i) do |j| substring = str[i..j] result << substring unless result.include?(substring) end end end end 
+3
source share
 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 version of your method and it works with smaller steps =)

+3
source share
 def substrings(str) (0...str.length).map do |i| (i...str.length).each { |j| str[i..j]} end end 

Another way to do this that reads to me is a little clearer.

+2
source share

Way later, but this is what I got from reformatting your code.

 def substrings(string) siz = string.length answer = [] (0..siz-1).each do |n| (n..siz-1).each do |i| answer << string[n..i] end end answer end 
0
source share

Here is a recursive way to get all possible substrings

 def substrings str return [] if str.size < 1 ((0..str.size-1).map do |pos| str[0..pos] end) + substrings(str[1..]) end 
0
source share

All Articles