1
votes

Comment fonctionne `each_cons` avec des chiffres uniques?

J'ai fait un kata sur CodeWars , dont le résumé est de prendre un nombre et de renvoyer " Jumping !! " si les chiffres sont à moins de 1 l'un de l'autre (par exemple 2345 code >, 4323 , 7898 ) et "Not !!" sinon. Tous les chiffres uniques (par exemple 5 , 7 , 9 ) sont des nombres sautants.

C'est l'une des meilleures solutions: p >

def jumping_number(n)
    n.to_s.chars.map(&:to_i).each_cons(2) { |x, y| return "Not!!" if (x - y).abs != 1 }
    return "Jumping!!"
end

Ceci est mon propre code:

def jumping_number(n)
    n.to_s.chars.map(&:to_i).each_cons(2).all? { |x, y| (x - y).abs == 1 } ? "Jumping!!" : "Not!!"
end

Je ne comprends pas comment each_con [sic] travaux. Comment la condition de ces méthodes peut-elle (correctement) retourner true lorsque n est un seul chiffre? Le consécutif est soit nil ou 0 qui, lorsqu'il est utilisé dans le calcul, ne doit pas renvoyer true , et pourtant c'est le cas. P >


2 commentaires

Le consécutif n'est ni 0 ni nil (il n'existe pas du tout). Si vous aviez une pomme et que je disais m'en donner 2 ou les à la fois, et je n'en accepterai que 2 à la fois, ou je n'accepterai rien, vous seriez coincé en me donnant rien car c'est physiquement impossible autrement ['apple']. each_cons (2) .to_a # => [] .


"Chaque roi des Etats-Unis est ..." est vrai quelle que soit la proposition que vous mettez "...". La phrase entière est satisfaite dans le vide.


3 Réponses :


5
votes

Voici votre malentendu:

Le consécutif est soit nul, soit 0 qui, lorsqu'il est utilisé dans le calcul, ne devrait pas renvoyer vrai (et pourtant c'est le cas!)

Ce n'est ni nul ni 0 . Cela n'existe tout simplement pas du tout. L'énumérateur est vide.

Malheureusement, cela n'est pas documenté dans la documentation de Enumerable # each_cons . La solution à votre casse-tête est que si la taille que vous demandez pour le contre est plus petite que la taille de l'énumérable, alors il n'y aura pas de contre:

[5, 6, 7].each_cons(2).to_a
#=> [[5, 6], [6, 7]]

[5, 6, 7].each_cons(3).to_a
#=> [5, 6, 7]

[5, 6, 7].each_cons(4).to_a
#=> []

En d'autres termes: le bloc n'est jamais exécuté, il n'y aura donc jamais d'erreur.


2 commentaires

... et l'autre solution mentionnée revient à [] .all? {} # => true (lorsque le tableau est de taille 1), c'est pourquoi cela fonctionne.


ne serait-il pas plus agréable que ruby ​​renvoie un élément nul si la taille de la requête est plus grande que le con? [5, 6, 7] .each_cons (4) .to_a # => [5, 6, 7, nil] ou au moins # => [ 5, 6, 7]



1
votes

Jörg a répondu à votre question, mais voici une autre façon d'effectuer le test.

123.digits                 #=> [3, 2, 1] 
123.to_s.chars.map(&:to_i) #=> [1, 2, 3]

Notez que j'ai utilisé Entier # chiffres plutôt que Entier # to_s pour séparer les chiffres:

def jumping_number(n)
  enum = n.digits.to_enum
  loop { return "Not!!" unless (enum.next - enum.peek).abs == 1 }
  "Jumping!!"
end     

jumping_number 5      #=> "Jumping!!" 
jumping_number 12321  #=> "Jumping!!" 
jumping_number 1243   #=> "Not!!"

Les ordres des éléments du tableau produit ne sont pas les mêmes, mais ce n'est pas grave pour ce problème.

Enumerator # peek déclenche une exception StopInteration lorsqu'il est exécuté après Enumerator # next a provoqué la génération du dernier élément de l'énumérateur. Kernel # loop puis gère l'exception en sortir de la boucle.


0 commentaires

0
votes

Une autre solution possible consiste à utiliser Enumerable #chunk_ while puis mesurer la taille du tableau retourné. Comment ça marche:

def jumping_number(n)
  n.digits.chunk_while{ |x, y| (x-y).abs == 1 }.to_a.size == 1 ? "Jumping!!" : "Not!!"
end

Donc, en l'utilisant dans une méthode:

[1,2,3].chunk_while{ |x, y| (x-y).abs == 1 }.to_a #=> [[1, 2, 3]]
[1].chunk_while{ |x, y| (x-y).abs == 1 }.to_a #=> [[1]]
[1,2,4].chunk_while{ |x, y| (x-y).abs == 1 }.to_a #=> [[1, 2], [4]]

(Merci @Cary Swoveland de se souvenir que Integer #digits existe.)


0 commentaires