2
\$\begingroup\$

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')
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Oct 1, 2017 at 7:05
\$\endgroup\$

3 Answers 3

4
\$\begingroup\$
  • In Ruby, there are enough Enumerable and Array 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 called substrings. Your title suggests leading_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"]
answered Oct 5, 2017 at 11:54
\$\endgroup\$
1
  • \$\begingroup\$ Oh, cool. Ok, thank you. And yes you are correct, it was leading substrings, not all the substrings. \$\endgroup\$ Commented Oct 7, 2017 at 2:10
4
\$\begingroup\$

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"]
answered Oct 3, 2017 at 3:54
\$\endgroup\$
4
  • \$\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\$ Commented 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\$ Commented 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\$ Commented Oct 7, 2017 at 2:11
  • \$\begingroup\$ Sure, do whatever you like with it :) \$\endgroup\$ Commented Oct 7, 2017 at 4:25
2
\$\begingroup\$

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
answered Oct 1, 2017 at 19:59
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Opening the String class is a very bad idea, known as monkey patching. One should never do this. \$\endgroup\$ Commented 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\$ Commented Oct 3, 2017 at 10:36
  • \$\begingroup\$ Oh, OK. Then the Ruby people must be very disciplined. \$\endgroup\$ Commented Oct 3, 2017 at 14:40

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.