2016-12-20 8 views
2

Учитывая следующее:Число в массиве не типизировано как целое?

def test(arr) 
    cache = [] 
    for i in 0..arr.length 
    if !cache[arr[i]] # no implicit conversion from nil to integer 
     cache[arr[i]] = true 
    end 
    if !cache[arr[i]].to_i # no implicit conversion from nil to integer 
     cache[arr[i]] = true 
    end 
    if !cache[arr[i].to_i] # works fine 
     cache[arr[i]] = true 
    end 
    end 
end 

puts test([1, 5, 8, 11]) 

Почему cache[arr[i]] требует to_i преобразования? От this answer

Ваша ошибка исходит из кода C внутри интерпретатора Ruby. Основной класс, реализованный на C, получает ноль, когда ожидает Integer. Он может иметь #to_i, но он не имеет #to_int, поэтому результатом является TypeError.

Я не вижу, как преобразование arr[i].to_i решает проблему, так как arr[i] уже является целым числом?

ответ

4

У вас проблемы с работой здесь, прежде всего потому, что вы используете for, и вы используете его неправильно. Как ни странно, for вряд ли когда-либо используется в Ruby. Вместо этого предлагается each и другие Перечисленные варианты.

Вот более Рубите идиоматическую версия коды:

def test(arr) 
    cache = [ ] 

    arr.each_with_index do |e, i| 
    cache[i] = true 
    end 

    cache 
end 

Вы можете даже реорганизовать это дальше, если вы делаете простое преобразование, где индекс не имеет значения:

def test(arr) 
    arr.map do |e| 
    true 
    end 
end 

Если вы проверили, какое значение принимали i во время каждой итерации вашего цикла, вы увидите, что он проползает мимо конца вашего массива и таким образом заканчивает возврат nil из-за звонка вне пределов. .to_i преобразует это обратно в 0, который прокладывает проблему, но не исправляет ее.

Если вы хотите использовать диапазоны, как, что использует 0...arr.length где оператор ... идет до , но не включает окончания границы.

+0

Я не могу согласиться с первым предложением. Проблема не имеет ничего общего с 'for' или ее неправильным использованием, это простая ошибка за один раз. Нет ничего * неправильного * с использованием 'for' или того, как он использует' for', он просто отговаривается в пользу '.each' * по соглашению *. Он столкнулся бы с той же проблемой, если бы использовал '(0..arr.length) .each do | i |' вместо использования 'for'. – meagar

+0

@meagar Я имею в виду использование 'for' в классическом смысле * приглашает * по очереди ошибки. Я не знаю, сколько битов кода C или C++ я видел с такими проблемами точно так же. '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'тоже безопасно. – tadman

+1

'for' также может быть надежным, и он абсолютно не требует ошибок при использовании правильно, так же, как' .each'. Если бы он использовал 'for i in arr', все было бы в порядке. Я полностью согласен с тем, что '.each' на сегодняшний день является более идиоматическим способом повторения перечислимого числа, но я по-прежнему не согласен с обвинениями в' 'для проблем здесь. – meagar

2

Возможно, проблема связана с тем, что итерация проходит один за концом вашего входного массива.

0..arr.length обрабатывает индексы 0, 1, 2, 3, 4 для вашего тестового примера. Последний элемент этого массива имеет индекс 3.

Я считаю, что вы хотите 0 ... arr.length, чтобы сделать это более разумным.

Обратите внимание ... во втором примере vs .. в вашем.

2

Вы обращаетесь к элементу, который не существует: первый индекс равен 0, последний индекс length-1, эрго arr[arr.length] не существует, и возвращает nil, что означает, что cache[arr[arr.length]] является cache[nil], а так cache массив и массивы индексируются целыми числами, он пытается преобразовать nil в целое число с использованием to_int, но терпит неудачу.

Непосредственное решение состоит в том, чтобы не перебирать до arr.length, либо путем создания открытого диапазона до arr.length-1, либо с использованием эксклюзивного ассортимента.

Но реальный ответ в том, что в любое время вы пишете цикл, вы делаете что-то не так, и есть метод в Enumerable API, что вам лучше использовать вместо этого. К сожалению, из вашего кода не совсем ясно, что он даже должен делать, прямо сейчас он просто возвращает диапазон и не имеет побочных эффектов, поэтому он почти ничего не делает.

Вы хотите что-то ищите?

def test(arr) 
    arr.each_with_object([]) do |el, acc| acc[el] = true end 
end 

test([1, 5, 8, 11]) 
#=> [nil, true, nil, nil, nil, true, nil, nil, true, nil, nil, true] 
+0

Это более точная реализация кода OP, чем фактический принятый ответ – engineersmnky

Смежные вопросы