2
\$\begingroup\$

The task is to enhance the Enumerable module with a method nth().

The method shall create a new list, which contains every nth-element of the object, when it is invoked.

For example: [2, 4, 6, 8, 10, 12].nth(2) shall return [4, 8, 12]

Here's my implementation:

module Enumerable
  def nth(n)
    i = 0
    ordinal = 1
    relevant_iteration = n * ordinal

    self.select do | num |
        i += 1

        if i == relevant_iteration
          ordinal += 1
          relevant_iteration = ordinal * n

          num
        end 
    end    
  end
end

print [2, 4, 6, 8, 10, 12].nth(2) # => [4, 8, 12]
print "\n"
print (4..12).nth(3)  # => [6, 9, 12]

It works as expected and it has passed the unit-tests.

But: My solution isn't elegant. At least that's my own impression.

  • Could my code be improved in regard to more compactness?
  • Is my code readable and understandable?
  • What could be improved?
\$\endgroup\$
  • \$\begingroup\$ This isn't exactly an answer because I feel like you're looking for something more complicated/interesting, but you could also do this with def nth(n); step(n).to_a; end \$\endgroup\$ – thesecretmaster Aug 3 at 18:39
3
\$\begingroup\$

nth slicing

Perhaps you could use a slice with map instead.

module Enumerable
  def nth(n)
    self.each_slice(n).select{|c| c.length == n}.map(&:last)   
  end
end

unit tests

print [2, 4, 6, 8, 10, 12].nth(3) # => [6, 12]
print "\n"
print [2, 4, 6, 8, 10].nth(3) # => [6]
print "\n"
print [2, 4, 6, 8].nth(3) # => [6]
print "\n"
print [2, 4, 6].nth(3) # => [6]
print "\n"
print [2, 4].nth(3) # => []
print "\n"

Rubocop Report

Skipping an iteration should be done like this..

 next unless i == relevant_iteration

    ordinal += 1
    relevant_iteration = ordinal * n

rather than..

if i == relevant_iteration
  ordinal += 1
  relevant_iteration = ordinal * n

General Guidelines:

  • use 2 spaces for indentation
  • frozen string
  • n as parameter name: min length should be 3 -> takeIndex instead?

Refactored

# frozen_string_literal: true

module Enumerable
  def nth(takeIndex)
    i = 0
    ordinal = 1
    relevant_iteration = takeIndex * ordinal

    self.select do |num|
      i += 1

      next unless i == relevant_iteration

      ordinal += 1
      relevant_iteration = ordinal * takeIndex

      num
    end
  end
end
\$\endgroup\$
  • 2
    \$\begingroup\$ You seem to have experience with a broad variety of programming languages. I really appreciate your participation here. \$\endgroup\$ – πάντα ῥεῖ Jul 28 at 9:28
  • \$\begingroup\$ @πάνταῥεῖ Thanks for this welcoming feedback. \$\endgroup\$ – dfhwze Jul 28 at 9:30
  • 1
    \$\begingroup\$ I dunno about renaming n to skip. In my mind, I would assume that skip=1 means "every second element". \$\endgroup\$ – 200_success Jul 29 at 5:37
  • \$\begingroup\$ @200_success you are right, skip is not the best name. I would personally accept n. But Ruby guidelines stipulate longer variable names. \$\endgroup\$ – dfhwze Jul 29 at 14:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.