PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Friday, November 11, 2022

[FIXED] How to pass unknown Proc recursively in Ruby

 November 11, 2022     algorithm, lambda, proc, recursion, ruby     No comments   

Issue

Problem

I am trying to write a method (Array#bubble_sort), that takes in an optional proc argument.
When given a proc, the method should sort the array according to the proc.
When no proc is given, the method should sort the array in increasing order.
Recursively, this works fine without adding a proc, however when given an unknown proc, I cannot find a way to pass it back through as an argument correctly.

Code

class Array
  def bubble_sort(&prc)

    prc = Proc.new{|a,b| a <=> b} if !prc

    self.each_with_index do |ele,idx|
      if prc.call(self[idx],self[idx+1]) == 1
        self[idx],self[idx+1] = self[idx+1], self[idx]
        self.bubble_sort(&prc) 
      end
    end

    self
    end
end

Test Code

[4, 12, 2, 8, 1, 14, 9, 25, 24, 81].bubble_sort returns the expected results of [1, 2, 4, 8, 9, 12, 14, 24, 25, 81]

[4, 12, 2, 8, 1, 14, 9, 25, 24, 81].bubble_sort { |a, b| a.to_s <=> b.to_s } returns a stack level too deep error instead of the expected result of [1, 12, 14, 2, 24, 25, 4, 8, 81, 9]


Solution

The issue is not with your passing of the proc, but rather that is that <=> works differently on numbers and strings.

When your loop gets to the end of the array, self.idx is equal to self.length - 1 and self.idx + 1 is equal to self.length. Calling self[self.length] on an array will always be nil, because of zero-indexing.

So, you end up calling proc.call(<last element of array>, nil)

The behavior of the spaceship operator differs depending on if you do number <=> nil or number.to_s <=> nil.to_s (which is the difference between the two procs you're comparing):

81 <=> nil
# => nil

81.to_s <=> nil.to_s
# => 1

In your case, you don't want any comparison with nil to result in a swap, so you have two options:

  1. You can change the proc to return nil if the second element is nil:

    arr.bubble_sort do |a,b|
      b.nil? ? nil : a.to_s <=> b.to_s
    end
    
  2. You can just skip the comparison altogether if b is out-of-bounds:

    self.each_with_index do |ele,idx|
      next if idx + 1 == self.length
      # ... other stuff
    


Answered By - max pleaner
Answer Checked By - Pedro (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing