Ruby Koan 151, делающий исключения
Я иду через рубиновые коаны, я на 151, и я просто ударил кирпичную стену.
Вот коан:
# You need to write the triangle method in the file 'triangle.rb'
require 'triangle.rb'
class AboutTriangleProject2 < EdgeCase::Koan
# The first assignment did not talk about how to handle errors.
# Let handle that part now.
def test_illegal_triangles_throw_exceptions
assert_raise(TriangleError) do triangle(0, 0, 0) end
assert_raise(TriangleError) do triangle(3, 4, -5) end
assert_raise(TriangleError) do triangle(1, 1, 3) end
assert_raise(TriangleError) do triangle(2, 4, 2) end
end
end
Тогда в triangle.rb имеем:
def triangle(a, b, c)
# WRITE THIS CODE
if a==b && a==c
return :equilateral
end
if (a==b && a!=c) || (a==c && a!=b) || (b==c && b!=a)
return :isosceles
end
if a!=b && a!=c && b!=c
return :scalene
end
if a==0 && b==0 && c==0
raise new.TriangleError
end
end
# Error class used in part 2. No need to change this code.
class TriangleError < StandardError
end
Я вне растерянности - любая помощь вообще будет очень оценена!
EDIT: Чтобы завершить этот коан, мне нужно поместить что-то в класс TriangleError, но я понятия не имею, что
ОБНОВЛЕНИЕ: вот что говорит koan karma:
<TriangleError> exception expected but none was thrown.
Ответы
Ответ 1
- Треугольник не должен иметь никаких сторон длины 0. Если это так, это либо отрезок линии, либо точка, в зависимости от того, сколько сторон равно 0.
- Отрицательная длина не имеет смысла.
- Любые две стороны треугольника должны содержать не более трех сторон.
- См. 3, и сосредоточьтесь на "больше".
Вам не нужно менять код TriangleError, AFAICS. Похоже, ваш синтаксис просто немного дурацкий. Попробуйте изменить
raise new.TriangleError
к
raise TriangleError, "why the exception happened"
Кроме того, вы должны тестировать значения (и бросать исключения), прежде чем что-либо делать с ними. Переместите материал исключения в начало функции.
Ответ 2
Вы забыли случай, когда a, b или c отрицательны:
def triangle(a, b, c)
raise TriangleError if [a,b,c].min <= 0
x, y, z = [a,b,c].sort
raise TriangleError if x + y <= z
[:equilateral,:isosceles,:scalene].fetch([a,b,c].uniq.size - 1)
end
Ответ 3
Закончено:
def triangle(a, b, c)
a, b, c = [a, b, c].sort
raise TriangleError if a <= 0 || a + b <= c
[nil, :equilateral, :isosceles, :scalene][[a, b, c].uniq.size]
end
Спасибо комментаторам здесь:)
Ответ 4
Мне нравится ответ Кори. Но мне интересно, есть ли какие-либо причины или что-то, что можно получить, имея четыре теста, когда у вас может быть два:
raise TriangleError, "Sides must by numbers greater than zero" if (a <= 0) || (b <= 0) || (c <= 0)
raise TriangleError, "No two sides can add to be less than or equal to the other side" if (a+b <= c) || (a+c <= b) || (b+c <= a)
Ответ 5
Вам не нужно изменять Исключение. Что-то вроде этого должно работать;
def triangle(*args)
args.sort!
raise TriangleError if args[0] + args[1] <= args[2] || args[0] <= 0
[nil, :equilateral, :isosceles, :scalene][args.uniq.length]
end
Ответ 6
def triangle(a, b, c)
[a, b, c].permutation do |sides|
raise TriangleError unless sides[0] + sides[1] > sides[2]
end
case [a,b,c].uniq.size
when 3; :scalene
when 2; :isosceles
when 1; :equilateral
end
end
Ответ 7
Вы определенно не обновляете класс TriangleError - я сам застрял на себе. Я думаю, мне нужно использовать здесь теорему pythag.
def triangle(a, b, c)
# WRITE THIS CODE
if a == 0 || b == 0 || c == 0
raise TriangleError
end
# The sum of two sides should be less than the other side
if((a+b < c) || (a+c < b) || (b+c < a))
raise TriangleError
end
if a==b && b==c
return :equilateral
end
if (a==b && a!=c) || (a==c && a!=b) || (b==c && b!=a)
return :isosceles
end
if(a!=b && a!=c && b!=c)
return :scalene
end
end
# Error class used in part 2. No need to change this code.
class TriangleError < StandardError
end
Ответ 8
Мне нужен метод, который анализировал все аргументы эффективно вместо того, чтобы полагаться на порядок, указанный в тестовых утверждениях.
def triangle(a, b, c)
# WRITE THIS CODE
[a,b,c].permutation { |p|
if p[0] + p[1] <= p[2]
raise TriangleError, "Two sides of a triangle must be greater than the remaining side."
elsif p.count { |x| x <= 0} > 0
raise TriangleError, "A triangle cannot have sides of zero or less length."
end
}
if [a,b,c].uniq.count == 1
return :equilateral
elsif [a,b,c].uniq.count == 2
return :isosceles
elsif [a,b,c].uniq.count == 3
return :scalene
end
end
Надеюсь, это поможет другим понять, что существует более одного способа кошки кошки.
Ответ 9
Попытайтесь понять, что я должен делать с koan 151, я получил его с первыми сообщениями и получаю много удовольствия, чтобы проверить каждое решение:)... вот моя минута:
def triangle(a, b, c)
array = [a, b, c].sort
raise TriangleError if array.min <= 0 || array[0]+array[1] <= array[2]
array.uniq!
array.length == 1 ? :equilateral: array.length == 2 ? :isosceles : :scalene
end
Koan - очень интересный способ узнать Ruby
Ответ 10
Я не думаю, что я вижу это здесь.
Я считаю, что все незаконные условия треугольника подразумевают, что самая длинная сторона не может превышать половины общего числа. то есть:
def triangle(a, b, c)
fail TriangleError, "Illegal triangle: [#{a}, #{b}, #{c}]" if
[a, b, c].max >= (a + b + c) / 2.0
return :equilateral if a == b and b == c
return :isosceles if a == b or b == c or a == c
return :scalene
end
Ответ 11
Я закончил с этим кодом:
def triangle(a, b, c)
raise TriangleError, "impossible triangle" if [a,b,c].min <= 0
x, y, z = [a,b,c].sort
raise TriangleError, "no two sides can be < than the third" if x + y <= z
if a == b && b == c # && a == c # XXX: last check implied by previous 2
:equilateral
elsif a == b || b == c || c == a
:isosceles
else
:scalene
end
end
Мне не нравится второе условие/рейз, но я не уверен, как его улучшить.
Ответ 12
Вы также можете попробовать исключить исключение с помощью:
raise TriangleError.new("All sides must be greater than 0") if a * b * c <= 0
Ответ 13
Действительно, в следующем коде условие a <= 0 избыточно. a + b всегда будет меньше c, если a < 0, и мы знаем, что b < с
raise TriangleError if a <= 0 || a + b <= c
Ответ 14
Вот что я написал, и все это работало нормально.
def triangle(a, b, c)
# WRITE THIS CODE
raise TriangleError, "Sides have to be greater than zero" if (a == 0) | (b == 0) | (c == 0)
raise TriangleError, "Sides have to be a postive number" if (a < 0) | (b < 0) | (c < 0)
raise TriangleError, "Two sides can never be less than the sum of one side" if ((a + b) < c) | ((a + c) < b) | ((b + c) < a)
raise TriangleError, "Two sides can never be equal one side" if ((a + b) == c) | ((a + c) == b) | ((b + c) == a)
return :equilateral if (a == b) & (a == c) & (b == c)
return :isosceles if (a == b) | (a == c) | (b == c)
return :scalene
end
# Error class used in part 2. No need to change this code.
class TriangleError < StandardError
end
Ответ 15
Вы должны проверить, что новый созданный треугольник не нарушает "неравенство треугольника". Вы можете убедиться в этом по этой маленькой формуле.
if !((a-b).abs < c && c < a + b)
raise TriangleError
end
Когда вы получите сообщение об ошибке:
<TriangleError> exception expected but none was thrown.
Ваш код, вероятно, бросает исключение, создавая правильный треугольник в этом файле. about_triangle_project.rb
Ответ 16
Для Koan about_triangle_project_2.rb нет необходимости изменять класс TriangleError. Вставьте этот код перед вашим треугольным алгоритмом, чтобы пройти все тесты:
if ((a<=0 || b<=0 || c<=0))
raise TriangleError
end
if ((a+b<=c) || (b+c<=a) || (a+c<=b))
raise TriangleError
end
Ответ 17
Это заняло некоторое время мозга. Но вот мое решение
def triangle(a, b, c)
# WRITE THIS CODE
raise TriangleError, "All sides must be positive number" if a <= 0 || b <= 0 || c <= 0
raise TriangleError, "Impossible triangle" if ( a + b + c - ( 2 * [a,b,c].max ) <= 0 )
if(a == b && a == c)
:equilateral
elsif (a == b || b == c || a == c)
:isosceles
else
:scalene
end
end
Ответ 18
Вот моя версия...: -)
def triangle(a, b, c)
if a <= 0 || b <= 0 || c <= 0
raise TriangleError
end
if a + b <= c || a + c <= b || b + c <= a
raise TriangleError
end
return :equilateral if a == b && b == c
return :isosceles if a == b || a == c || b == c
return :scalene if a != b && a != c && b != c
end
Ответ 19
Вот что я закончил. Это своего рода сочетание нескольких из приведенных выше примеров с моим собственным уникальным признаком исключения треугольника (оно также рассматривает вырожденный случай). Кажется, работает.
def triangle(a, b, c)
raise TriangleError if [a,b,c].min <= 0
raise TriangleError if [a,b,c].sort.reverse.reduce(:-) >= 0
return :equilateral if a == b && b == c
return :isosceles if a == b || a == c || b == c
return :scalene
end
Ответ 20
Вот мой изящный ответ, с большой помощью от комментариев выше
def triangle(a, b, c)
test_tri = [a,b,c]
if test_tri.min <=0
raise TriangleError
end
test_tri.sort!
if test_tri[0]+ test_tri[1] <= test_tri[2]
raise TriangleError
end
if a == b and b == c
:equilateral
elsif a != b and b != c and a != c
:scalene
else
:isosceles
end
end
Ответ 21
#(1)Any zero or -ve values
if [a,b,c].any? { |side_length| side_length <= 0 }
raise TriangleError
end
#(2)Any side of a triangle must be less than the sum of the other two sides
# a < b+c, b < a+c and c < a+b a valid triangle
# a >= b+c, b >= a+c and c >= a+b an invalid triangle
total_of_side_lengths = [a,b,c].inject {|total,x| total += x}
if [a,b,c].any? { |side_length| side_length >= (total_of_side_lengths - side_length)}
raise TriangleError
end
Ответ 22
Не то, чтобы этот вопрос нуждался в другом ответе; однако, я думаю, что это самое простое и читаемое решение. Спасибо всем, кто передо мной.
def triangle(a, b, c)
a, b, c = [a, b, c].sort
raise TriangleError, "all sides must > 0" unless [a, b, c].min > 0
raise TriangleError, "2 smaller sides together must the > 3rd side" unless a + b > c
return :equilateral if a == b && a == c
return :isosceles if a == b || a == c || b == c
return :scalene
end
# Error class used in part 2. No need to change this code.
class TriangleError < StandardError
end
Ответ 23
Леон выигрывает на элегантной элегантности, Бенджи за свои знания API Array. Вот мой грубый элегантный ответ:
def triangle(a, b, c)
[a, b, c].each { | side | raise TriangleError, "Sides must be positive" unless side > 0 }
raise TriangleError, "Two sides can never be less than or equal to third side" if ((a + b) <= c) | ((a + c) <= b) | ((b + c) <= a)
return :equilateral if (a == b) && (b == c)
return :isosceles if (a == b) || (b == c) || (a == c)
return :scalene
end
Ответ 24
Нет необходимости изменять код TriangleError для любой задачи. Вам просто нужно проверить недействительные треугольники и поднять ошибку, если треугольник отсутствует.
def triangle(a, b, c)
if a==0 && b==0 && c==0
raise TriangleError, "This isn't a triangle"
end
if a <0 or b < 0 or c <0
raise TriangleError, "Negative length - thats not right"
end
if a + b <= c or a + c <= b or b + c <= a
raise TriangleError, "One length can't be more (or the same as) than the other two added together. If it was the same, the whole thing would be a line. If more, it wouldn't reach. "
end
# WRITE THIS CODE
if a == b and b == c
return :equilateral
end
if (a==b or b == c or a == c)
return :isosceles
end
:scalene
end
Ответ 25
В StackOverflow есть некоторые абсолютно блестящие люди... Мне напомнили об этом каждый раз, когда я посещаю: D
Просто чтобы внести свой вклад в разговор, вот решение, которое я придумал:
def triangle(a, b, c)
raise TriangleError if [a,b,c].min <= 0
x,y,z = [a,b,c].sort
raise TriangleError if x + y <= z
equal_sides = 0
equal_sides +=1 if a == b
equal_sides +=1 if a == c
equal_sides +=1 if b == c
# Note that equal_sides will never be 2. If it hits 2
# of the conditions, it will have to hit all 3 by the law
# of associativity
return [:scalene, :isosceles, nil, :equilateral][equal_sides]
end
Ответ 26
ваш предыдущий метод треугольника должен появиться здесь
class TriangleError < StandardError
end
def triangle(x,y,z)
if(x>=y+z||y>=x+z||z>=x+y)
raise TriangleError,"impossible triangle"
elsif(x==0&&y==0&&z==0)||(x<0||y<0||z<0)
raise TriangleError,"length cannot be zero or negative"
elsif(x==y&&x==z)
:equilateral
elsif(x==y||y==z||x==z)
:isosceles
else
:scalene
end
end
Ответ 27
Вот мое решение... честно говоря, я не могу придумать более краткий и понятный!
def triangle(a, b, c)
raise TriangleError unless a > 0 && b > 0 && c > 0
raise TriangleError if a == b && a + b <= c
raise TriangleError if a == c && a + c <= b
return :equilateral if a == b && b == c
return :isosceles if a == b || b == c || c == a
:scalene
end
Ответ 28
Правила:
Код:
raise TriangleError if ( [a,b,c].any? {|x| (x <= 0)} ) or ( ((a+b)<=c) or ((b+c)<=a) or ((a+c)<=b))
[:equilateral, :isosceles, :scalene].fetch([a,b,c].uniq.size - 1)
Ответ 29
Не нужно писать метод TriangleError. В нем говорится: "Не нужно менять этот код", поэтому я его вообще не изменю. Упрямый, как я.
4 линии застрелили его, красиво и чисто.
def triangle(a, b, c)
if(a * b * c <= 0) || (( (a + c)<=b) || ((a + b)<=c)||((b + c)<=a) )
raise TriangleError else
return ((a == b && b == c && a == c)? :equilateral:(((a == b)||(b == c)||(a == c))? :isosceles: :scalene))
end
end
# Error class used in part 2. No need to change this code.
class TriangleError < StandardError
end
Ответ 30
def triangle(a, b, c)
raise TriangleError if [a, b, c].min <= 0
raise TriangleError if [a, b, c].max * 2 >= [a, b, c].reduce(:+)
if a == b && b == c
:equilateral
elsif a == b || b == c || c == a
:isosceles
else
:scalene
end
end