2014-08-15 2 views
2

Мне нужно проверить, равна ли сумма любых двух элементов массива заданному числу. Это то, что я придумал, но это, кажется, не сделать сравнениеСравните суммы элементов в массиве: Ruby

def sum_comparison(int_array, x) 
    n = int_array.length 
    (0..n).each do |i| 
    (1..n).each do |j| 
     if ((int_array[i].to_i + int_array[j].to_i) == x) 
     return true 
     else 
     return false 
     end 
    end 
    end 
end 
+0

В чем Ваш вопрос? – sawa

+0

Код, который я написал, не работает правильно, мне нужен кто-то, чтобы намекнуть, где ошибка – codingal

+0

Как используется 'sum_comparison'? Что такое 'int_array_length'? – sawa

ответ

7

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

n = int_array.length 
(0..n).each do |i| 
    # use int_array[i].to_i inside the loop 
end 

Теперь внутри цикла each, вы будете получите цифры i = 0, 1, 2, ..., n, например, для int_array = [3,4,5] вы получите i = 0, 1, 2, 3. Обратите внимание, что есть четыре элемента, потому что вы начали отсчет с нуля (это называется отключением на одну ошибку). Это в конечном итоге приведет к доступу к массиву в n, который находится за пределами массива. Это снова приведет к возврату nil, что, вероятно, связано с тем, что вы используете to_i, чтобы преобразовать это обратно в целое число, потому что в противном случае вы получите TypeError: nil can't be coerced into Fixnum, когда сделаете добавление. То, что вы, вероятно, хотел вместо этого было просто:

int_array.each do |i| 
    # use i inside the loop 
end 

Для примера массива [3,4,5] это будет на самом деле привести к i = 3, 4, 5. Чтобы получить комбинации массива в более рубиновом режиме, вы можете, например, использовать Array#combination. Кроме того, вы можете использовать Array#any?, чтобы обнаружить, если какой-либо из комбинаций удовлетворяют заданному условию:

def sum_comparison(array, x) 
    array.combination(2).any? do |a, b| 
    a + b == x 
    end 
end 
+1

> любые 2 элемента – zishe

+0

@zishe спасибо за ваш комментарий, исправить его. –

+2

Есть ли основания для используйте перестановку, а не комбинацию? Последний является подмножеством первого, и этого достаточно, чтобы его можно было рассмотреть. – sawa

5

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

def sum_comparison(int_array, x) 
    n = int_array.size 
    (0...n).each do |i| 
    (1...n).each do |j| 
     if (int_array[i].to_i + int_array[j].to_i) == x 
     return true 
     end 
    end 
    end 
    false 
end 

Для упрощения этого вы можете использовать permutation или combination и any? методы, как @ p11y предлагает. Чтобы получить основанные элементы, вы можете использовать find or detect.

def sum_comparison(a, x) 
    a.combination(2).any? { |i, j| i + j == x } 
end 

a.combination(2).detect { |i, j| i + j == x } 
# sum_comparison([1,2,3, 4], 6) => [2, 4] 
+0

Небольшой комментарий к первому (длинному) решению: вы всегда будете проходить через все элементы, вы могли бы «возвращать истину», когда совпадение было найдено, и просто написать «false» в конце метода. Это позволяет вам прекратить рано. Ваше предложение об использовании 'detect' очень полезно. –

+0

Да, спасибо, надо упомянуть. – zishe

3

Использование нумератор:

#!/usr/bin/env ruby 

def sum_comparison(int_array, x) 
    enum = int_array.to_enum 
    loop do 
    n = enum.next 
    enum.peek_values.each do |m| 
     return true if (n + m) == x 
    end 
    end 
    false 
end 

puts sum_comparison([1, 2, 3, 4], 5) 

Выход:

true 
+0

Зачем это должно быть более эффективным? –

+0

@ p11y Просто мои мысли на самом деле жаль. По крайней мере, мне легче изобразить. – konsolebox

+0

Я хочу сказать, что, хотя ваш код верен, вы используете только API более низкого уровня, чтобы выполнить одно и то же. Ваш код не закончится раньше или что-то еще. Однако у меня проблема с этим, потому что он вводит более синтаксический шум. –

1

Проблема

Ваш метод эквивалентно:

def sum_comparison(int_array, x) 
    return int_array[0].to_i + int_array[1].to_i == x 
end 

Таким образом,

int_array = [1,2,4,16,32,7,5,7,8,22,28] 
sum_comparison(int_array, 3) #=> true, just lucky! 
sum_comparison(int_array, 6) #=> false, wrong! 

Alternative

Здесь является относительно эффективным РЕАЛИЗАЦИЯ, конечно, гораздо более эффективно, чем использование Enumerable#combination.

Код

def sum_comparison(int_array, x) 
    sorted = int_array.sort 
    smallest = sorted.first 
    sorted_stub = sorted.take_while { |e| e+smallest <= x } 
    p "sorted_stub = #{sorted_stub}" 
    return false if sorted_stub.size < 2 
    loop do 
    return false if sorted_stub.size < 2 
    v = sorted_stub.shift 
    found = sorted_stub.find { |e| v+e >= x } 
    return true if found && v+found == x 
    end 
    false 
end 

Примеры

sum_comparison([7,16,4,12,-2,5,8], 3) 
    # "sorted_stub = [-2, 4, 5]" 
    #=> true 
sum_comparison([7,16,4,12,-2,5,8], 7) 
    # "sorted_stub = [-2, 4, 5, 7, 8]" 
    #=> false 
sum_comparison([7,16,4,22,18,12,2,41,5,8,17,31], 9) 
    # "sorted_stub = [2, 4, 5, 7]" 
    #=> true 

Примечания

  • Линия p "sorted_stub = #{sorted_stub}" включается просто для отображения массива sorted_stub в примерах.

  • e+smallest > x Если для любых элементов f и g в sorted, для которых g >= e и f < g, f+g >= e+smallest > x. Ergo, sorted_stub.last - это самое большое значение в sorted, которое необходимо учитывать.

  • Для заданного значения v, линия found = sorted_stub.find { |e| v+e >= x } останавливает поиск второго значения e, для которого v+e = x как только он находит e такое, что v+e >= x. Следующая строка затем определяет, найдено ли совпадение.

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