8
votes

Le mot le plus long ruby ​​en tableau

J'ai construit cette méthode pour trouver le mot le plus long dans un tableau, mais je me demande s'il y a une meilleure façon de l'avoir fait. Je suis plutôt nouveau à Ruby, et je fais juste cela comme un exercice d'apprentissage de la méthode injecter .

Il renvoie le mot le plus long dans une matrice ou un tableau des mots les plus longs égaux. xxx


0 commentaires

6 Réponses :


7
votes

Ruby a une méthode standard pour renvoyer un élément dans une liste avec le maximum d'une valeur. xxx

ou vous pouvez utiliser la méthode max_by xxx

pour obtenir tous les éléments avec la longueur maximale xxx


2 commentaires

C'est bien, mais l'OP "a juste fait cela comme un exercice d'apprentissage de la méthode d'injecte."


Les deux méthodes renvoient uniquement un seul élément, pas un tableau de certaines cordes tout aussi longues.



2
votes

une doublure à deux: xxx pré>

ou si vous voulez utiliser l'injection, cela utilise votre idée, mais c'est plus court. P>

test_array.inject{ |ret,word|
   ret = [ret] unless ret.kind_of?(Array)

   ret << word  if word.size == ret.first.size
   ret = [word] if word.size > ret.first.size
   ret
}


3 commentaires

Cette méthode n'est pas idempotente lorsqu'elle est appliquée directement sur un tableau. Probablement pas ce que vous attendez. Vous pouvez utiliser un clone ici. Mais la solution est correcte et probablement même pas la plus lente (sans connaître les détails de la mise en œuvre de la méthode intégrée GROUP_BY )


@Holger: group_by utilise des recherches de tableau, donc c'est fondamentalement o (n) , tandis que le tri est plus lent.


Au lieu de delete_if , vous pouvez utiliser Take_whIle qui s'arrête dès qu'il atteint un mot plus petit.



1
votes
module Enumerable
  def longest_word
    (strings = map(&:to_s)).
      zip(strings.map(&:length)).
      inject([[''],0]) {|(wws, ll), (w, l)|
        case  l <=> ll
        when -1 then [wws, ll] 
        when  1 then [[w], l]
        else         [wws + [w], ll]
        end
      }.first
  end
end
This method only depends on generic Enumerable methods, there's nothing Array specific about it, therefore we can pull it up into the Enumerable module, where it will also be available for Sets or Enumerators, not just Arrays.

2 commentaires

Cela renvoie un seul élément, pas un éventail de mots avec des tailles égales.


@steenslag: Ouais, merci d'avoir remarqué. Le nom de la méthode m'a jeté un peu, j'aurais attendu une méthode qui retourne plusieurs mots à appeler longest_words (pluriel).



29
votes

Je ferais

class Array
  def longest_word
    group_by(&:size).max.last
  end
end


8 commentaires

Si vous êtes sûr que vous n'avez que des chaînes, vous pouvez l'écrire comme self.group_by (& longueur) .max.last sinon vous auriez besoin d'un additionnel appel comme Self.group_by {| el | el.to_s.Size} .max.last . Et enfin, pour renvoyer une seule chaîne lorsque vous n'avez qu'un seul élément, vous pouvez faire longest_word.size> 1? Longest_word: longest_word.first avant de revenir.


Joli! J'ai pris la liberté de faire le code plus concis, mais s'il vous plaît revenir si vous n'aimez pas le style


L'OP a dit dans la question qu'il a fait cela afin d'apprendre injecter , et il n'est pas tout à fait clair s'il cherchait une meilleure façon d'utiliser injecter ou juste une meilleure façon période. Le vôtre est une jolie réponse à la deuxième interprétation et @mladen Jablanović à la première. Les deux obtiennent mon +1.


Cela a commencé avec moi avec moi jouant avec injecter , mais voyant qu'il y a des moyens plus courts de le faire sans cette méthode est intéressante. Merci!


@ Marc-André Lafortune Il est beaucoup plus lisible de cette façon, merci.


Vous voudrez peut-être vérifier cela aussi Lien


@Inlamazab min_by (et max_by ) renvoie une seule valeur, celle-ci renvoie un tableau avec une ou plusieurs valeurs.


@steenslag Depuis que je vous ai vu avoir seulement la dernière valeur, je pensais que mentionner l'autre réponse en vaut la peine. Merci pour l'indice.



4
votes

Voici un en utilisant injecter code> (ne fonctionne pas pour un tableau vide):

words.inject(['']){|a,w|
  [a + [w], [w], a][w.length <=> a.last.length]
}


4 commentaires

En fait, ce devrait travailler pour un tableau vide, c'est-à-dire (un) du (s) point (s) d'alimenter explicitement une valeur initiale pour l'accumulateur.


Dans ma version, je pensais en quelque sorte qu'il serait beaucoup plus propre de enfiler les longueurs de mots implicitement à travers l'accumulateur, mais cela n'a pas beaucoup nettoyé beaucoup :-) Vous avez l'air beaucoup plus agréable.


Afin de travailler pour des tableaux vides, il faudrait reculer injecter avec un tableau vide (plutôt qu'un tableau contenant une chaîne vide comme je le fais) et compliquer la ramification à l'intérieur d'un peu plus. Mais à des fins d'apprentissage injecter , je pensais que c'était suffisant.


Ah, oui, cela rendra un mauvais résultat. Je pensais plus sur Haskell, où plipl1 lancera une erreur lorsque FLETL ne sera pas ou ma solution qui appelle premier à la suite de Le injecter , qui serait nil pour un tableau vide sans un accumulateur initial explicite et augmentez ainsi un nométhoderror . (Je devrais apprendre à ne pas répondre à des questions ou laissez des commentaires dans une précipitation, avec ma veste sur, littéralement à mi-chemin de la porte :-))



0
votes

Cette solution utilise la méthode d'injection pour accumuler les cordes les plus longues dans une matrice, puis les ramasse avec la longueur la plus élevée.

animaux = ["souris", "chat", "oiseau", "ours", "orose"]

animaux.Inject (hash.new {| h, k | h [k] = []}) {| ACC, E | ACC [E.SIZE] << e; ACC} .sort.Last [1]

Ce retour: ["souris", "souris"]


0 commentaires