9
votes

Le moyen le plus rapide de sauter des lignes tout en analysant les fichiers de Ruby?

J'ai essayé de chercher cela, mais je ne pouvais pas trouver grand chose. Cela semble être quelque chose qui a probablement été demandé auparavant (plusieurs fois?), Alors je m'excuse si c'est le cas.

Je me demandais ce que le moyen le plus rapide d'analyser certaines parties d'un fichier de rubis serait. Par exemple, supposons que je connaisse les informations que je souhaite pour une fonction particulière se situe entre les lignes 500 et 600 de, par exemple, un fichier de 1000 lignes. (Évidemment, ce type de question est orienté vers de nombreux fichiers importants, je suis simplement en train d'utiliser ces plus petits chiffres pour l'exemple), car je sais que ce ne sera pas au premier semestre, est-il un moyen rapide de ne pas tenir compte de cette information ?

J'utilise actuellement quelque chose sur les lignes de: xxx

Ça marche, mais je ne peux tout simplement pas m'empêcher de mieux fonctionner .

Je suis très nouveau à Ruby et je suis intéressé à apprendre de nouvelles façons de faire les choses dedans.


0 commentaires

4 Réponses :


0
votes

sonne comme rio peut être utile ici. Il vous fournit une méthode lignes () .


4 commentaires

Cela itère juste sur les lignes. Ce n'est pas très utile dans cette situation.


@coreyward: pourquoi pas? Vous pouvez transmettre une gamme et itérair ces lignes. Y a-t-il quelque chose qui me manque?


La bibliothèque IO intégrée fait la même chose.


@coreyward: Je ne comprends toujours pas, désolé. L'OP demande à d'autres moyens de ne lire que certaines lignes de fichiers d'un fichier. Ma réponse échoue-t-elle à cela? Vous avez suggéré quelque chose comme rechercher , ce qui ne fonctionnera pas si vous ne pouvez pas savoir combien d'octets vous devriez sauter (par exemple, vous ne savez pas combien de temps chaque enregistrement).



0
votes

Vous pouvez utiliser io # # Readlines , qui renvoie un tableau avec toutes les lignes

f = File.new(file_in)
f.readlines[500..600].each do |line| 
  #line is each line in the file (including the last \n)
  #stuff
end


2 commentaires

Ce n'est pas très favorable aux grands fichiers. Construire un tableau avec 500 000 entrées Tout simplement pour accéder de 230 000 à 230 100,100 n'est pas intelligent. Si quelque chose, itérant sur chaque ligne dans le flux et les jeter au besoin, c'est plus intelligent car le fichier ne se chargait pas en mémoire tout à la fois.


Cela pourrait être ma mise en œuvre (et bien sûr, je vais continuer à tester quand j'ai du temps), mais cette méthode semble être un peu plus lente, même sur de petits fichiers d'environ 2000 lignes. Cela dit, la différence est assez petite à ces niveaux (quand j'ai fait f = fichiers.Nouveau ... Readlines [x....y] ... il a fallu ~ 0,85 secondes moyenne; la méthode initiale que j'ai postée me donne environ 0.75Seconde moyenne) bien sûr, je ne le ferais peut-être pas correctement ou très bien. Je vais faire d'autres tests.



1
votes

Je ne sais pas s'il y a un moyen équivalent de faire cela pour les lignes, mais vous pouvez utiliser rechercher ou le décalage de décalage sur un objet IO sur "Skip "octets.

voir io # recherche ou voir io # ouvrir pour des informations sur l'argument de décalage.


1 commentaires

Pour savoir où une ligne se termine (avec un caractère EOL), il n'y a aucun moyen de sortir, vous devez lire le fichier octet-byte, puis déposer les informations de lecture. Si vous recherchez au 1000e octet, vous n'avez aucun moyen de dire combien de lignes vous avez sauté. Il peut être 400 ou 1 ou même zéro.



11
votes
file.lines.tap{|enum| 500.times{enum.next}}.take(100)

6 commentaires

Cela a l'air plus rubish! J'avais vraiment pensé à cela après avoir posté la question - le fait que les "lignes" ne soient pas vraiment définies par rien d'autre que "l'espace entre" nouvelles lignes "caractères" (ou plutôt avant et après). Ce qui signifierait qu'ils doivent tous être analysés pour ce personnage de toute façon. Je suppose que si j'avais une idée générale de l'espace précédant les lignes requises, dans les bits / octets / peu importe, je pouvais sauter cette zone, puis commencer à analyser la ligne par ligne, mais pour le moment, je vais accepter que cela fonctionne assez bien comme est. Ou comme si je serai avec une ligne plus agréable comme la vôtre! Merci.


En fait, vous pourrait utiliser rechercher si les lignes contenaient des informations relatives à leur position dans le fichier (telles que les numéros de ligne ou les horodatages triés). Ensuite, vous pourriez tirer une variante de la recherche binaire. Vous pouvez ouvrir une autre question si cela aiderait dans votre cas particulier.


Cela conduit cependant à des problèmes d'évolutivité. Si le fichier comporte plusieurs millions de lignes, il va être lu complètement dans la mémoire avant de pouvoir goutte . Cela pourrait être lent et rendre la machine ne répond pas comme sa chargement des données ou remplissez toute la mémoire disponible si les lignes sont longues, provoquant une pagination. Pour une approche plus sûre avec un fichier texte, vous ferez mieux de les lire une ligne à la fois, sautez-les jusqu'à ce que vous atteigniez ceux que vous souhaitez, capturez uniquement les lignes nécessaires.


@L'imin man: Qu'est-ce qui vous fait penser qu'il a besoin de charger un fichier entier afin de goutte ?


goutte est dans tableau , ce qui impliquait qu'il a dû avoir un silencieux sur d'abord. Je viens d'envisager et que le tableau obtient de énumérable et le code source indique qu'il boucle sur son bloc (n) épuiser le résultat. Donc, il n'a pas à tout charger en mémoire; Il faut charger les lignes de manière séquentielle et les jeter. Et, comme vous le dites, il existe différentes façons de l'écrire, mais le résultat final est identique, les lignes sont en lecture juste pour être comptées. Et, c'était mon point, que les lignes de lecture skient individuellement un problème d'évolutivité, vs. slurping un fichier qui peut tuer un hôte.


Pour Ruby 2.0.0P247, vous devez utiliser chaque_line: AVERTISSEMENT: IO # Les lignes sont obsolètes; utiliser #each_line à la place