2015-11-24 2 views
2

У меня возникают проблемы с ситуациями, в которых мне нужно сравнить два элемента в массиве с помощью методов. Я нахожу логику довольно простой, просто используя вложенный цикл, но это, вероятно, не очень хорошо использует Ruby.Сравнение двух элементов в массиве с Ruby

Для примера. Определите, если массив имеет любую пару из 2 чисел, которые равны 0:

def pairs(array) 
    i = 0 
    while i < array.length 
    y = i + 1 
    while y < array.length 
     if array[i] + array[y] == 0 
     return true 
     end 
     y += 1 
    end 
    i += 1 
    end 
    return false 
end 

Или, если я хотел, чтобы увидеть, если две вещи в массиве идентичны, я хотел бы использовать ту же логику, за исключением набора: если массив [я] == к массиву [y] ...

Может ли кто-нибудь предоставить лучший метод для такой проблемы?

+0

Пара чисел не может быть равна нулю. Они могут быть равны нулю, имеют сумму, разницу, продукт или коэффициент, равный нулю, один по модулю другой может равняться нулю ... После прочтения вашего кода (который мне не нужно делать, чтобы понять вопрос), я вижу вас означает, что два числа суммируются до нуля. –

ответ

11

Часто вы можете перевести английскую спецификацию прямо в Ruby.

В вашем первом вопросе вы спрашиваете, добавляет ли какая-либо комбинация из двух элементов к нулю. Способ использования, когда вы хотите узнать, является ли что-то истинным для любого элемента перечислимого типа, - Enumerable#any?. Если вы хотите работать с комбинациями элементов из массива, вы используете метод Array#combination. Для суммирования вы можете использовать Numeric#+ или Enumerable#inject, и если вы хотите узнать, является ли число равным нулю, вы можете использовать Numeric#zero?.

Таким образом, возможная реализация первого вопроса будет:

ary.combination(2).any? {|pair| pair.inject(:+).zero? } 

Ваш второй вопрос можно ответить следующим образом:

ary.combination(2).any? {|a, b| a == b } 

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

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

+1

Спасибо за 'Array # сочетание' – Aetherus

0

Если вы просто хотите посчитать occurencies Элемента в массиве вы можете использовать Enumerable#count

a = [1,2,3,4,5,1,2,2] 
a.count(2) 
# => 3 

теперь, если вы хотите увидеть, если есть повторяющиеся записи в массиве можно использовать метод uniq

def has_duplicates?(arr) 
    arr.uniq.length == arr.length 
end 
+0

Не имеет отношения к вопросу. – Aetherus

+0

@Aetherus Я не вижу, как это не имеет значения. Первая часть объясняет на примере, как увидеть, есть ли более одного вхождения элемента в массиве, 'a.count (0)' вернет желаемый результат. (Что является первым вопросом) Вторая часть определяет, равны ли два элемента массива, что совпадает с checkink для дубликатов в массиве. (Какой второй вопрос) – xlembouras

0

Вот мой подход к вашему первому вопросу, а другой метод, который возвращает пары:

def pairs?(arr) 
    arr.inject(false){|c, v| c || (arr.include?(-v) && v > 0)} 
end 

def get_pairs(arr) 
    arr.collect{|val| [val, -val] if arr.include?(-val) && val > 0}.reject(&:nil?) 
end 

arr = [1, 8, -2, 12, -15, 5, 3] 
p pairs?(arr) 
p get_pairs(arr) 

arr = [1, 8, -2, 12, -15, 5, 3, 2, -3, 1] 
p pairs?(arr) 
p get_pairs(arr) 

Выход:

false 
[] 
true 
[[3, -3], [2, -2]] 

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

0

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

Код

def pairs(arr) 
    arr.map { |e| e < 0 ? -e : e }. 
     group_by(&:itself). 
     select { |_,v| v.size > 1 }. 
     keys 
end 

Примеры

pairs [1, 8, -2, 12, -15, 5, 3]   #=> [] 
pairs [1, 8, -2, 12, -15, 5, 3, 2, -3, 1] #=> [1, 2, 3] 

Если вы хотите, чтобы второй пример для возврата [[1, -1], [2, -2], [3, -3]] (хотя я не вижу смысла), заменяющие предпоследняя строка метод с:

map { |k,_| [k, -k] } 

Объяснение

шаги для:

arr = [1, 8, -2, 12, -15, 5, 3, 2, -3, 1] 

являются:

a = arr.map { |e| e < 0 ? -e : e } 
    #=> [1, 8, 2, 12, 15, 5, 3, 2, 3, 1] 
b = a.group_by(&:itself) 
    #=> {1=>[1, 1], 8=>[8], 2=>[2, 2], 12=>[12], 15=>[15], 5=>[5], 3=>[3, 3]} 

Мы получили Object#itself в Руби v2.2. Для более ранних версий, используйте:

b = a.group_by { |e| e } 

Продолжение:

c = b.select { |_,v| v.size > 1 } 
    #=> {1=>[1, 1], 2=>[2, 2], 3=>[3, 3]} 
c.keys 
    #=> [1, 2, 3] 

Строка:

select { |_,v| v.size > 1 } 

может быть написано:

select { |k,v| v.size > 1 } 

где k и v repres «ключ» и «значение», но поскольку k не используется в расчете блока, принято заменять k локальной переменной _ (да, это переменная - попробуйте в IRB), в основном для информирования читателя что аргумент не используется в блоке.

Если arr = [1, 1, -1, -1, 2, -2], это вернет [1,2]. Если вы хотите, чтобы он вернулся [1,1,2], вы должны принять другой подход.

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