Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

string

ruby

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.

like image 724
Jimmy Huang Avatar asked Dec 22 '10 10:12

Jimmy Huang


People also ask

How do I split a string into substrings?

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.


3 Answers

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).

like image 77
tokland Avatar answered Nov 15 '22 21:11

tokland


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 =)

like image 22
user2566402 Avatar answered Nov 15 '22 21:11

user2566402


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
like image 31
Mladen Jablanović Avatar answered Nov 15 '22 19:11

Mladen Jablanović