理解Ruby类:“未定义的方法”<'为真:TrueClass“

时间:2013-02-14 21:27:45

标签: ruby methods quicksort

我正在关注Coursera课程,我正在尝试在Ruby中实现quicksort算法。我对语言和OOP的概念都很陌生。

我创建了两个函数:一个是quickSort函数,它调用分区例程(根据作为数组第一个元素的pivot将数组拆分为两个子数组)。

最终我将把这两个方法放在一个类Array下,但是现在我认为这样就行了。

我尝试在一个数组上运行它(a = [5,4,3,2,1]),但是我遇到了以下错误:

A2.rb:16:in `partition': undefined method `<' for true:TrueClass (NoMethodError)
    from A2.rb:15:in `each'
    from A2.rb:15:in `partition'
    from A2.rb:33:in `quickSort'

这是我的代码:

    def partition(array, left_idx, right_idx)
      num_comp = array.length - 1
      p = array[left_idx]
      i = left_idx + 1
      j = left_idx + 1
      puts "#{left_idx}, #{right_idx}, #{array[j]} #{j}"
      puts "pivot = #{p}"
      for j in (left_idx + 1..right_idx)
        if (left_idx < j < right_idx and left_idx < i < right_idx)
          if (array[j] > p)
            j = j + 1
          else 
            array[i], array[j] = array[j], array[i]
            i = i + 1
            j = j + 1
          end
        end
      end
      #swap pivot and rightmost value in subarray that contains < p
      array[1], array[i] = array[i], array[1]
      pivot_idx = i
      return array, num_comp, pivot_idx
    end

    def quickSort(array, start_idx, end_idx)
      array_n, num_comp, pivot_idx = partition(array, start_idx, end_idx)
      left_array = array_n[start_idx..pivot_idx - 1]
      right_array = array_n[pivot_idx + 1..end_idx]
      if (left_array.length > 1) 
        array_n = quickSort(array_n, start_idx, pivot_idx - 1)
      end
      if (right_array.length > 1)
        array_n = quickSort(array_n, pivot_idx + 1, end_idx)
      end
      return array
    end

    #a = Array.new()
    a = [5, 4, 3, 2, 1]
    quickSort(a, 0, 4)
    print "Array"
    puts a

由于

4 个答案:

答案 0 :(得分:4)

left_idx < j < right_idx

你不能这样做。

left_idx&lt; j首先解析为“True”

然后表达式变为真&lt; right_idx和&lt;是一个无效的运算符..

将expresison更改为if left_idx&lt; j&amp;&amp; j&lt; right_idx

答案 1 :(得分:2)

你不能这样做:

left_idx < j < right_idx and left_idx < i < right_idx

你需要建立条件:

((j > left_idx) && (j < left_idx)) && (etc)

答案 2 :(得分:0)

问题在于这一行:

if (left_idx < j < right_idx and left_idx < i < right_idx)

这是有效的数学,但是无效的Ruby(在大多数其他编程语言中也是无效的)。你想要的是:

if (left_idx < j and j < right_idx and left_idx < i and i < right_idx)

正在发生的是Ruby解释“&lt;”作为一种方法。因此,原始行变为:

if ((left_idx.<(j)).<(right_idx)) and ((left_idx.<(i)).<(right_idx))

在您的情况下,(left_idx。&lt;(j))的结果为“true”。所以它然后尝试调用&lt;在“真正的”类中,它不存在,导致你得到的错误。

答案 3 :(得分:0)

问题在于这一行:

(left_idx < j < right_idx and left_idx < i < right_idx)

left < middle < right可能是人们通常用数学写的东西,但在Ruby中,<并不特别 - 它只是一种方法。具体来说,返回布尔值的方法。 left_idx < j的结果始终为true或false,然后您尝试将right_idx与该值进行比较。显然,这没有任何意义。

您可以将该行写为

left_idx < j && j < right_idx #...

(left_idx..right_idx).include? j && (left_idx..right_idx).include? i

([i,j].all? {|v| (left_idx..right_idx).include? v})

编写quicksort的一种更惯用的方法是

def quicksort(arr)
   pivot, *rest = arr
   left,right = rest.partition{|v| v<pivot}.map{|a| if !a.empty? then quicksort(a) else a end}
   left.push(pivot) + right
end

这可能仍然可以做得更好。请注意,这不是就地快速排序,但你的似乎也不是。