7

In Ruby, I'd like to convert a slash-separate String such as "foo/bar/baz" into ["foo/bar/baz", "foo/bar", "foo"]. I already have solutions a few lines long; I'm looking for an elegant one-liner. It also needs to work for arbitrary numbers of segments (0 and up).

Yehuda Katz
  • 28,535
  • 12
  • 89
  • 91

4 Answers4

12
"foo/bar/baz".enum_for(:scan, %r{/|$}).map {Regexp.last_match.pre_match}
sepp2k
  • 363,768
  • 54
  • 674
  • 675
4

The highest voted answer works, but here is a slightly shorter way to do it that I think will be more readable for those not familiar with all the features used there:

a=[]; s.scan(/\/|$/){a << $`}

The result is stored in a:

> s = 'abc/def/ghi'
> a=[]; s.scan(/\/|$/){a << $`}
> a
["abc", "abc/def", "abc/def/ghi"]

If the order is important, you can reverse the array or use unshift instead of <<.

Thanks to dkubb, and to the OP for the improvements to this answer.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • On ruby 1.8.7 the result is only #=> "abc/def/ghi" and not the array as specified in the answer – nas Feb 13 '10 at 09:50
  • 2
    @nas: The return value will be the string in any version of ruby. The requested array will be in the `a` variable. If you were aware of that and were just nitpicking, feel free to ignore my comment. – sepp2k Feb 13 '10 at 10:15
  • 2
    You could simplify the code in the block further by doing: a=[]; 'abc/def/ghi'.scan(/\/|$/){a<<$`} – dkubb Feb 13 '10 at 10:23
  • I'm accepting this with the caveat that using unshift would eliminate the need for a reverse :) – Yehuda Katz Feb 13 '10 at 20:55
  • 1
    @Yehuda Katz: Using unshift this will become O(n^2) instead of O(n) (I'm assuming that scan can go linearly through the string with the given regex), so using reverse should be much more efficient. – sepp2k Feb 14 '10 at 11:22
0

Not quite as efficient as the chosen answer, and gives [] when given an empty string, rather than [""], but its a real one liner :P

s.split('/').inject([]) { |a,d| a.unshift( [a.first,d].compact.join('/') ) }
Ben Marini
  • 2,633
  • 1
  • 21
  • 13
0
->(l,s,z){
    ( t = s[/#{z}.[^\/]*/] ) && [l[l,s,t], t]
}.tap{ |l|
    break l[l,'a/b/c','']
}.flatten.compact
Nakilon
  • 34,866
  • 14
  • 107
  • 142