【问题标题】:undefined method 'shift' for class nil:NilClass in RubyRuby 中类 nil:NilClass 的未定义方法“shift”
【发布时间】:2013-07-26 15:15:34
【问题描述】:

我正在尝试运行一个 mincut 算法(对于一个类),这适用于较小的测试用例,但是每当我放置一个更大的测试用例(最终导致分配问题)时,我都会收到以下错误:

"(eval):1049: nil:NilClass (NoMethodError) 的未定义方法 `shift'"

我怀疑在某些情况下程序可能会崩溃,但我无法弄清楚。如果有人可以帮助我,那就太好了!

a = [[1, 2, 3, 4, 7], [2, 1, 3, 4], [3, 1, 2, 4], [4, 1, 2, 3, 5], [5, 4, 6, 7, 8], [6, 5, 7, 8], [7, 1, 5, 6, 8], [8, 5, 6, 7]]

mincut = 8
count = 10

def clean(a, i, j)                        #When collapsing two nodes together, scans
    z = a[j][0]                           #all elements and changes value of second
    m = a[i][0]                           #index to first, i.e. all 2's become 1's. 
    a.each_index do |x|
        a[x].each_index do |y|
            if a[x][y] == z
            a[x][y] = m
            end
        end
    end
end

def delete_loops!(a, i)                   #scans concatenated array, removes all duplicates of the first element
    z = a[i].shift
        a[i].reject!{ |item| item == z}
    a[i].unshift(z)
end

def collapse!(a, i, j)          #collapses two nodes together
    clean(a, i, j)
    a[i].concat(a[j])           #concatenates the second array into the first
    a.delete_at(j)              #deletes second array
    delete_loops!(a, i)
end

def random(a)                   #picks random nodes to collapse, and returns their 
    t = rand(a.size)            #positions in the array.
    s = a[t][1 + rand(a[t].size - 1)]
    for x in 0..a.size-1
        if a[x][0] == s
        s = x
        break
        end
    end
return t, s
end

for x in 0..count do            #repeats the program x amount of times, returns
    while a.size > 2 do         #the lowest value of the minimum cut.
        i, j = random(a)
        collapse!(a, i, j)
    end
    size = a[0].size - 1

    if size < mincut
        mincut = size
    end
end
puts mincut

总结该程序,它通过执行一定数量的运行并保留返回的最小切割来计算图中的最小切割。似乎很麻烦的区域是我的“delete_loops!”函数,它本质上检查一个数组以查看是否有任何元素与数组的第一个元素匹配,然后删除所述第一个元素的重复项。我使用“shift”和“unshift”方法来做到这一点(通过删除然后重新插入第一个元素,我在不删除过程中的第一个元素时遇到了麻烦)。

我认为要么是某种情况导致它崩溃,要么是我执行它的方式给我带来了麻烦。有什么想法吗?

    #edit: full error message, from the codecademy scratchpad

(eval):1122: undefined method `shift' for nil:NilClass (NoMethodError)
    from (eval):1131:in `collapse!'
    from (eval):1149
    from (eval):1146:in `each'
    from (eval):1146

#and from my command line try (reading a text file with same array):

test.rb:29:in 'delete_loops!" : undefined method 'shift' for nil:NilClass <NoMethodError>
    from test.rb:38:in 'collapse!'
    from test:rb:56:in 'block in <main>'
    from test.rb:53:in 'each'
    from test.rb:53:in '<main>'

【问题讨论】:

  • 发布完整的堆栈跟踪。
  • 很明显,'a' 是 nil,所以我会放入一些断言来验证参数是否有意义(a 不是 nil,并且 i 在范围内)。如果断言失败,您可以备份以查找问题。
  • 在调试此类问题时,我建议使用调试器。它对单步执行代码和检查实时值有很多的帮助。
  • 在哪里可以找到调试器?我去了 Ideone.com,它只是给了我相同的输出
  • 请注意,for x in 0..count do 应该是 (count+1).times do |x|。在 Ruby 中使用 for 构造是非常不寻常的。记住0..count[0, 1, 2, ... count],或者0..2[0, 1, 2],所以你可能会在这里遇到一个错误。

标签: ruby function methods


【解决方案1】:

有时分配给变量 i 的随机值是最后一个可能的数组元素。

所以当崩溃! a.delete_at(j) 变量 i 是否指向最后一个元素的索引 + 1 (也就是说没有元素,因为它现在超出了缩短数组的范围)

我想你希望 i 指向同一个元素,不管它在数组中的位置已经改变,因为元素 j 被删除了,所以...

在delete_at和对delete_loops的调用之间添加以下减量!...处理i指向的数组不再在同一位置的情况...

a.delete_at(j)
i -= 1 if i >= j
delete_loops!(a, i)

想一想,如果分配给 i 和 j 的随机数相等,你也会有问题......

所以您可能希望将调用更改为折叠!...

collapse!(a, i, j) if i != j

【讨论】:

    猜你喜欢
    • 2023-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-15
    • 2013-03-04
    • 2013-02-17
    相关资源
    最近更新 更多