Je traverse les koans Ruby, je suis sur 151 et je viens de frapper un mur de briques.
Voici le koan:
# 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's 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
Alors dans triangle.rb nous avons:
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
Je suis plus que confus - toute aide serait très appréciée!
EDIT: Pour compléter ce koan, je dois mettre quelque chose dans la classe TriangleError - mais je ne sais pas quoi
MISE À JOUR: Voici ce que dit le karma koan:
<TriangleError> exception expected but none was thrown.
Vous ne devriez pas avoir besoin de changer le code TriangleError, AFAICS. On dirait que votre syntaxe est juste un peu farfelue. Essayez de changer
raise new.TriangleError
à
raise TriangleError, "why the exception happened"
En outre, vous devriez tester les valeurs (et générer des exceptions) avant de faire quoi que ce soit avec elles. Déplacez le truc d'exception au début de la fonction.
Vous avez oublié le cas où a, b ou c sont négatifs:
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
J'ai fini par faire ceci:
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
Merci aux commentateurs ici :)
J'aime la réponse de Cory. Mais je me demande s'il y a une raison ou quelque chose à gagner à avoir quatre tests, alors que vous pourriez en avoir deux:
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)
Vous n'avez pas besoin de modifier l'exception. Quelque chose comme ça devrait marcher;
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
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
Après avoir essayé de comprendre ce que je devais faire avec koan 151, je l’ai compris avec les premiers posts, et je me suis amusé à vérifier la solution pour tout le monde :) ... voici la mine:
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 est un moyen très intéressant d'apprendre Ruby
Je ne pense pas que je vois celui-ci ici, pour le moment.
Je crois que toutes les conditions de triangle illégales impliquent que le côté le plus long ne peut être plus de la moitié du total. c'est à dire:
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
Je voulais une méthode qui analyse efficacement tous les arguments au lieu de s’appuyer sur l’ordre donné dans les assertions de test.
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
J'espère que cela aidera les autres à comprendre qu'il existe plus d'une façon de dépouiller un chat.
Vous ne devez certainement pas mettre à jour la classe TriangleError - je suis bloqué sur 152 moi-même. Je pense que je dois utiliser le théorème de pythag ici.
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
J'ai fini avec ce code:
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
Je n'aime pas la deuxième condition/relance, mais je ne sais pas comment l'améliorer.
En fait, dans le code suivant, la condition a <= 0 est redondante. a + b sera toujours inférieur à c si a <0 et nous savons que b <c
raise TriangleError if a <= 0 || a + b <= c
Vous pouvez également essayer d'instituer l'exception avec:
raise TriangleError.new("All sides must be greater than 0") if a * b * c <= 0
Voici ma réponse élégante, avec beaucoup d'aide des commentaires ci-dessus
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
Voici ma version ... :-)
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
Non pas que cette question avait besoin d'une autre réponse; Cependant, je pense que c'est la solution la plus simple et la plus lisible. Merci à tous ceux qui sont devant moi.
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
#(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
Celui-ci a pris un certain temps cerveau. Mais voici ma solution
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
C'est ce que j'ai fini avec. C'est en quelque sorte une combinaison de quelques-uns des exemples ci-dessus avec ma propre interprétation de l'exception d'inégalité de triangle (elle considère également le cas dégénéré). Semble travailler.
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
Voici ce que j'ai écrit et tout a bien fonctionné.
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
def triangle(a, b, c)
sides = a, b, c # Assigns variable signs (array) to all arguments.
begin
raise TriangleError if sides.inject(:+) <= 0 # Raise an error if all sides added together are less than or equal to 0. (the triangle would be invalid).
raise TriangleError if sides.any?(&:negative?) #Raise an error if there are any negative sides.
sides.each {|side| (side < (sides.inject(:+) - side) ? nil : (raise TriangleError))} # For the final check, Raise an error if any single side is greater than the other two sides added together. It can be broken down like this if side is less than (remaining sides - side we're comparing) raise an error, else, nil.
return :equilateral if sides.uniq.length == 1
return :isosceles if sides.uniq.length == 2
return :scalene if sides.uniq.length == 3
resuce TriangleError
end
end
Pour Koan about_triangle_project_2.rb, il n'est pas nécessaire de changer de classe TriangleError. Insérez ce code avant votre algorithme triangle pour réussir tous les tests:
if ((a<=0 || b<=0 || c<=0))
raise TriangleError
end
if ((a+b<=c) || (b+c<=a) || (a+c<=b))
raise TriangleError
end
Vous devez vérifier que le nouveau triangle créé ne rompt pas "l'inégalité du triangle". Vous pouvez vous en assurer grâce à cette petite formule.
if !((a-b).abs < c && c < a + b)
raise TriangleError
end
Lorsque vous obtenez l'erreur:
<TriangleError> exception expected but none was thrown.
Votre code génère probablement une exception lors de la création d'un triangle régulier dans ce fichier. about_triangle_project.rb
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
Ceci est ma solution: -
def triangle(a, b, c)
if a <= 0 || b <= 0 || c <= 0 || a + b <= c || a + c <= b || b + c <= a
raise TriangleError
elsif (a == b) &&( a==c) && (b==c)
return :equilateral
elsif (a==b) || (b==c) || (a==c)
return :isosceles
else
return :scalene
end
end
J'espère que ça aide.
Règles:
la taille doit être> 0
Total de 2 côtés, doit être plus grand que le 3ème
Code:
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)
La vérification d'erreur essaie d'obtenir les critères d'un triangle:
if (a <= 0 || b <= 0 || c <= 0)
raise TriangleError,"All lengths must be positive"
end
args=[a,b,c].sort #this lets us get at the longest side of the triangle
unless ( args[0]+args[1] > args[2] )
raise TriangleError,"Longest length may not be greater than the sum of the other lengths"
end
if (args[0]-args[1] > args[2])
raise TriangleError,"Longest length must be greater than the difference of the other two lengths"
end
Il existe des moyens plus élégants et concis de vérifier les erreurs, mais je pense que cela devrait indiquer clairement comment vérifier les 4 critères principaux: En fait, j'ai regroupé 2 critères en un seul. Par exemple. aucun côté ne peut être négatif et aucun côté ne peut être 0.
Utiliser un opérateur splat pour les arguments est un bon moyen de s'assurer que vous avez un tableau sans en former explicitement, mais je ne l'aime pas ici car cela signifie que vous devez également ajouter une coche pour vous assurer qu'il y a exactement 3 arguments, ce qui est implicite. maintenant.
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
Leon gagne sur l'élégance de fantaisie, Benji pour sa connaissance de l'API Array. Voici ma brute élégante réponse:
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
La plus petite solution que je pourrais trouver.
Cela passera les tests, cependant, il ne se plaindra pas si le tableau est plus long que prévu. Facile à tester mais ne semblait pas entièrement nécessaire.
def(sides*)
splat (transforme l'entrée en tableau)raise TriangleError if ... or ...
Déclenche l'erreur si l'une ou l'autre est vraiesides.sort!
trier la liste en place. Ceci est important car deux déclarations reposent sur le tri de la liste, ce qui signifie qu’il ne l’est fait qu’une fois.sides.sort![0] <=0
récupère le plus petit élément, s'il est supérieur à 0, tous les autres le seront.sides.reverse.reduce(:-) >=0
élément le plus important moins les deux plus petits, s'il est supérieur à 0, le plus grand des côtés est plus grand que les deux autres.sides.uniq.size-1
obtenir le nombre de côtés uniques (moins un)[:e,:i,:s].fetch(sides.uniq.size-1)
récupère l'élément approprié dans le tableau (et retourne).
def triangle(*sides)
raise TriangleError if sides.sort![0] <=0 or sides.reverse.reduce(:-) >=0
[:equilateral, :isosceles, :scalene].fetch(sides.uniq.size - 1)
end
Vous pouvez utiliser cette formule et valider tous les cas:
et vous codez comme:
def triangle(a, b, c)
# Validate the triangle
raise TriangleError, "The triangle is not valid" unless (a + b) > c && (a + c) > b && (b + c) > a
if a === b && b === c
:equilateral
elsif a === b || a === c || b === c
:isosceles
else
:scalene
end
end
Ma solution, je pense que c'est l'une des plus lisibles:
def triangle(a, b, c)
a, b, c = [a, b, c].sort
if a <= 0 or c >= a + b
raise TriangleError
end
case [a, b, c].uniq.length
when 1
:equilateral
when 2
:isosceles
when 3
:scalene
end
end
Voici ma solution ... honnêtement, je ne vois pas de solution plus concise et lisible!
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
Il y a des gens absolument géniaux sur StackOverflow ... Cela me rappelle chaque fois que je visite: D Pour contribuer à la conversation, voici la solution que j'ai proposée:
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
Pas besoin de changer le code TriangleError pour l'un ou l'autre défi. Il vous suffit de vérifier les triangles non valides et de générer l'erreur si le triangle ne l'est pas.
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
Pas besoin d'écrire la méthode TriangleError. Il dit "Pas besoin de changer ce code", donc je ne le changerai pas du tout. Têtu comme je suis.
4lines a tiré, Nice nd clean.
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