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).
+4
A:
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
2010-02-13 09:25:42
On ruby 1.8.7 the result is only #=> "abc/def/ghi" and not the array as specified in the answer
nas
2010-02-13 09:50:24
@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
2010-02-13 10:15:28
You could simplify the code in the block further by doing: a=[]; 'abc/def/ghi'.scan(/\/|$/){a<<$`}
dkubb
2010-02-13 10:23:34
I'm accepting this with the caveat that using unshift would eliminate the need for a reverse :)
Yehuda Katz
2010-02-13 20:55:37
@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
2010-02-14 11:22:21
+9
A:
"foo/bar/baz".enum_for(:scan, %r{/|$}).map {Regexp.last_match.pre_match}
sepp2k
2010-02-13 09:27:44
A:
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
2010-02-13 22:40:51