web-dev-qa-db-fra.com

Ruby Koan 151 levant des exceptions

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.
42
Elliot
  1. Un triangle ne doit pas avoir de côtés de longueur 0. Si c'est le cas, il s'agit d'un segment de droite ou d'un point, en fonction du nombre de côtés égaux à 0.
  2. La longueur négative n'a pas de sens.
  3. Les deux côtés d'un triangle doivent représenter plus que le troisième côté.
  4. Voir 3 et concentrez-vous sur le "plus".

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.

48
cHao

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
29
Sergey

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 :)

11
Leon Fedotov

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)
9
Matt Connolly

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
7
tomblomfield
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
6
Josh

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

4
Vielinko

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
3
Jon Carter

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.

3
Ben Campbell

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
3
Justin Miller

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.

2
Wejn

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
2
Serg

Vous pouvez également essayer d'instituer l'exception avec:

raise TriangleError.new("All sides must be greater than 0") if a * b * c <= 0
2
Juanjo

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
1
Chaos

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
1
rahul286

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
macsteps
  #(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
1
ryan

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
1
Yogi

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
1
user1138

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
1
Cory LaNou
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
1
Michael G

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
1
djblue2009

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

1
cycreator

votre méthode de triangle précédente devrait apparaître ici

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
0
javeria

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.

0
Himanshu Tiwari

Règles: 

  1. la taille doit être> 0

  2. 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)
0
jules345

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.

0
wmsmith
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
0
BenMliang

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
0
Isaac Rabinovitch

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. 

  1. def(sides*) splat (transforme l'entrée en tableau)
  2. raise TriangleError if ... or ... Déclenche l'erreur si l'une ou l'autre est vraie
  3. sides.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.
  4. sides.sort![0] <=0 récupère le plus petit élément, s'il est supérieur à 0, tous les autres le seront.
  5. 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.
  6. sides.uniq.size-1 obtenir le nombre de côtés uniques (moins un)
  7. [: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
    
0
DarkArk

Vous pouvez utiliser cette formule et valider tous les cas:

  • a + b> c
  • a + c> b
  • b + c> a

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
0
Luis Cortés

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
0
Tom Busby

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
0
Simone

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 
0
agustinMichael

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
0
Will

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
0
cold_farmer