I have a couple of answers that I wrote up for this exercise. Both of my methods work. I'm hoping to get some feedback on each and how I could improve them, if needed.
The idea is to take a string, such as 'abc' and return an array like this: ['a', 'ab', 'abc']
For the second method, I used #map
, but I'm not sure if this is the best way to achieve my desired result.
def substrings(string)
subbed = []
(0..string.length-1).each do |i|
subbed.push(string.slice(0..i))
end
return subbed
end
def substrings2(string)
string.split('').map.with_index do |c,i|
string.slice(0..i)
end
end
print substrings2('abc')
3 Answers 3
- In Ruby, there are enough
Enumerable
andArray
methods that you virtually never need to initialize an empty array and iterate to push values. - Your method doesn't return every substring in the string.
'bc'
isn't present for example. Your method shouldn't be calledsubstrings
. Your title suggestsleading_substrings
.
Here's a clear, short way to initialize this array with Array.new
:
def leading_substrings(string)
Array.new(string.size) { |i| string[0..i] }
end
p leading_substrings('abc')
# ["a", "ab", "abc"]
-
\$\begingroup\$ Oh, cool. Ok, thank you. And yes you are correct, it was leading substrings, not all the substrings. \$\endgroup\$Nathan– Nathan2017年10月07日 02:10:20 +00:00Commented Oct 7, 2017 at 2:10
What you're looking for is known as a "scan" in functional programming. Surprisingly, ruby's Enumerable
, which is where this method belongs (since what you're doing is not, ultimately, specific to strings), does not provide a scan
method or its equivalent.
But we can write one easily enough:
module Enumerable
def scans
reduce([]) {|m,x| m << (m.last || []) + [x]}
end
end
Now we have a general purpose method which we can use like so:
[9] pry(main)> (1..5).to_a.scans
=> [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
Your original problem now becomes a simple delegation to scans
:
[14] pry(main)> 'abc'.split('').scans.map(&:join)
=> ["a", "ab", "abc"]
-
\$\begingroup\$ It's a great idea if
Enumerable#scans
is used in other places with other objects than strings. Otherwise, it's a bit of an overkill, with many temp objects and methods. \$\endgroup\$Eric Duminil– Eric Duminil2017年10月05日 12:02:01 +00:00Commented Oct 5, 2017 at 12:02 -
1\$\begingroup\$ Yes, if you're just trying to solve the given problem, it's overkill. The point is that if you're a functional programmer, you recognize this immediately as a scan, and it just happens to be a deficiency of Enumerable that it lacks a scan method. So i just created the method I should have had anyway, and now I have a clean 1 line solution, albeit not the most performant one. Fwiw, for just the problem at hand, I do prefer your solution. \$\endgroup\$Jonah– Jonah2017年10月05日 15:09:13 +00:00Commented Oct 5, 2017 at 15:09
-
\$\begingroup\$ This is great. I'm still new to programming, so got a lot to learn before I'M able to switch careers. @Jonah is it ok if I copy this? I need to pick it apart and learn how it works on a deeper level. \$\endgroup\$Nathan– Nathan2017年10月07日 02:11:53 +00:00Commented Oct 7, 2017 at 2:11
-
\$\begingroup\$ Sure, do whatever you like with it :) \$\endgroup\$Jonah– Jonah2017年10月07日 04:25:39 +00:00Commented Oct 7, 2017 at 4:25
Your second method is closer to idiomatic Ruby. In general, you should never need to initialize an array. chars
is a nice alternative to split('')
. And, you can open String and add a new method. I would do:
class String
def substrings
chars.map.with_index { |_char, index| slice(0..index) }
end
end
Then:
'abc'.substrings
-
1\$\begingroup\$ Opening the
String
class is a very bad idea, known as monkey patching. One should never do this. \$\endgroup\$Roland Illig– Roland Illig2017年10月03日 05:58:23 +00:00Commented Oct 3, 2017 at 5:58 -
\$\begingroup\$ This is not correct. Monkey patching a class with a related method is considered normal practice in Ruby (and is prevalent throughout Rails). I generally recommend using refinements to achieve the same thing, but it is more complex than needed for this example. \$\endgroup\$Dan Kohn– Dan Kohn2017年10月03日 10:36:10 +00:00Commented Oct 3, 2017 at 10:36
-
\$\begingroup\$ Oh, OK. Then the Ruby people must be very disciplined. \$\endgroup\$Roland Illig– Roland Illig2017年10月03日 14:40:38 +00:00Commented Oct 3, 2017 at 14:40