Cet article a été rédigé en consultant les articles suivants. J'ai essayé de résoudre un problème de programmation simple en utilisant la correspondance de modèle Ruby --Qiita
L'article ci-dessus
"1, 5, 10-12, 15, 18-20"
À partir de la chaîne de caractères
[1, 5, 10, 11, 12, 15, 18, 19, 20]
Il décrit comment obtenir le tableau dans Ruby.
D'un autre côté, cet article est le contraire. En d'autres termes, lorsqu'un tableau d'entiers positifs est donné, il est trié, puis les numéros de série sont reliés par des tirets pour créer une chaîne de caractères séparés par des virgules.
Ce processus est utilisé, par exemple, pour créer la notation de numéro de page pour un index de livre.
De plus, dans une telle notation,
4-5
même s'il n'y a que deux numéros de série tels que 4, 5Il existe deux styles possibles, mais dans cet article, nous prendrons le premier (écrire également sur le second).
J'ai également écrit le code de test en utilisant test-unit.
require "test/unit"
def gather(array)
array.uniq.sort
.chunk_while{ |a, b| a.succ == b }
.map{ |c| (c.size == 1) ? c : "#{c[0]}-#{c[-1]}" }
.join(", ")
end
#Ci-dessous le code de test
#Si vous exécutez le script, le test décrit ci-dessous sera effectué automatiquement.
class TestGather < Test::Unit::TestCase
test "Démembré" do
assert_equal "1, 3, 5", gather([3, 5, 1])
end
test "Il y a duplication" do
assert_equal "2, 4", gather([4, 2, 2, 4, 4])
end
test "Résumé" do
assert_equal "1-2", gather([2, 1])
assert_equal "1-3", gather([2, 3, 1])
assert_equal "2-4, 7, 9, 11-12",
gather([12, 11, 7, 9, 2, 4, 3])
end
end
En premier
array.uniq.sort
En conséquence, la duplication est omise et le tri est effectué. Je ne pense pas qu'il faille beaucoup d'explications.
Cependant, compte tenu de l'efficacité, il convient de noter qu'il vaut mieux d'abord ʻuniq puis
trier` [^ uniq-sort].
[^ uniq-sort]: Pas très différent s'il y a peu de doublons. Cependant, il peut être doctrinal de se souvenir de «.uniq.sort».
Ensuite, le cœur de ce code est
chunk_while{ |a, b| a.succ == b }
Partie de. En fait, la référence officielle [Enumerable # chunk_ While](https://docs.ruby-lang.org/ja/2.7.0/method/Enumerable/i/chunk_ while.html) a un exemple qui ressemble exactement au code de cet article. Bien que cela ait été fait.
chunk_ while
est une méthode très intéressante de type Ruby. Qui est chunk_ while
?
Pour un objet Enumerable tel qu'un tableau, il s'agit d'une décision de lécher
Par exemple
[2, 6, 0, 3, 5, 8]
Disons qu'il y a un arrangement appelé, et nous voulons le diviser en catégories paires et impaires. En d'autres termes
[[2, 6, 0], [3, 5], [8]]
Je veux un tableau appelé. L'important est que seuls les ** égales et cotes ** adjacentes ** soient ** catalysées. Par conséquent, le dernier "8" n'est pas combiné avec "2, 6, 0", mais est un point de saut.
Au fait, comment écrire l'expression conditionnelle selon laquelle les deux entiers ʻa et
b` sont "les deux sont pairs ou les deux sont impairs"?
Une façon est
(a.even? && b.even?) || (a.odd? && b.odd?)
Mais vous n'avez pas à faire ce genre de problème. Si vous remarquez que "la différence entre pair et pair est paire", "la différence entre impair et impair est paire" et "la différence entre pair et impair est impaire"
(a - b).even?
Je sais que ça va.
Maintenant, pour obtenir un tableau de catamari pairs et impairs adjacents, écrivez comme suit en utilisant chunk_ while
.
numbers = [2, 6, 0, 3, 5, 8]
p numbers.chunk_while{ |a, b| (a - b).even? }.to_a
# => [[2, 6, 0], [3, 5], [8]]
Comment fonctionne ce chunk_ while
?
chunk_ while
utilise ʻeachpour récupérer chaque élément du récepteur. Tout d'abord, faites-le pour extraire les deux éléments. Dans ce cas, "2" et "6" sont récupérés. Passez ces deux au bloc et évaluez le bloc. Alors "(2-6). Même?" Est-ce vrai. A ce moment,
chunk_ whiledécide," Hmmmm, alors je ne me déconnecterai pas entre "2" et "6". " Ensuite, passez le «6» déjà récupéré et le «0» récupéré suivant au bloc. Encore une fois, le bloc renvoie vrai, donc il ne se déconnecte pas. De même, transmettez «0» et «3» au bloc, qui renvoie false. Ensuite,
chunk_ while` décide," Okay! Coupe-le ici! ".
La même chose s'applique ci-dessous.
La façon dont chunk_ while
prend deux éléments adjacents tout en décalant leurs positions un par un est similaire à ʻeach_cons (2). ʻEach_cons (2)
ne prend que deux éléments, tandis que chunk_ while
prend deux éléments pour déterminer où rejoindre / déconnecter.
Maintenant que vous savez comment fonctionne chunk_ while
chunk_while{ |a, b| a.succ == b }
Considérons.
ʻInteger # succ est une méthode qui renvoie un entier obtenu en ajoutant 1 à lui-même. ʻA.succ == b
exprime la condition que "après ʻa est
b`".
Suivant
map{ |c| (c.size == 1) ? c : "#{c[0]}-#{c[-1]}" }
Est facile.
Oups, un mot avant ça. Puisque la valeur de retour de chunk_ While
est un objet Enumerator, il n'est pas nécessaire d'en faire un tableau avec to_a
, et map
peut être continué telle quelle.
Au fait, concernant ce bloc map
, si chaque catamari a une longueur de 1, il est laissé tel quel, et s'il est égal ou supérieur à 2, le début et la fin sont reliés par un trait d'union.
Par exemple, «[7]» est laissé comme «[7]» et «[2, 3, 4]» est remplacé par «« 2-4 »». Eh bien, le tableau converti est un peu désagréable car les éléments sont des tableaux et des chaînes. Non, cela ne pose aucun problème (décrit plus loin), mais il est certain que ce sera un peu mou.
finalement
join(", ")
En finir avec.
Eh bien, il ne s'agit que de connecter les éléments avec ", "
, mais pour être sûr que vous avez dit dans le paragraphe précédent que "les éléments peuvent être des tableaux ou des chaînes, peu importe", Array # join nécessite une compréhension précise.
join
renvoie une chaîne connectée avec un argument intermédiaire si tous les éléments sont des chaînes.
Si certains des éléments ne sont pas des chaînes, ils sont d'abord convertis en chaînes avant d'être connectés, mais s'ils sont des tableaux, ils sont convertis en caractères en utilisant join
au lieu de to_s
. À ce moment-là, les mêmes arguments que la «jointure» d'origine sont utilisés pour la «jointure».
Alors
p [1, [2, 3]].join("-") # => "1-2-3"
devenir de cette façon.
Avec ce qui précède, le fonctionnement est parfaitement compris.
Comme je l'ai prédit dans la section "Introduction", comment puis-je le modifier pour qu'il ne soit pas groupé avec des tirets alors qu'il n'y a que deux nombres consécutifs tels que "4,5"?
En d'autres termes
p gather([1, 2, 4, 5, 6]) # => "1, 2, 4-6"
Comment le faire
En fait, l'exemple de code pour [Enumerable # chunk_ While](https://docs.ruby-lang.org/ja/2.7.0/method/Enumerable/i/chunk_ While.html) est écrit selon ce style.
Faire cela
.map{ |c| (c.size == 1) ? c : "#{c[0]}-#{c[-1]}" }
À
.map{ |c| (c.size < 3) ? c : "#{c[0]}-#{c[-1]}" }
Vous pouvez le changer en. Il ressort clairement des spécifications de «jointure» déjà mentionnées que seule cette modification est requise.
Il est malheureux que la bibliothèque de tests unitaires similaires de Ruby reste divisée en unité de test et minitest.
A mes yeux, le test-unit semble être meilleur [^ tu], mais Rails a adopté minitest (une modification magique de celui-ci?), Donc minitest peut être supérieur au monde. inconnue.
[^ tu]: Avec test-unit, vous pouvez donner le nom du test sous forme de chaîne de caractères comme dans cet article, et vous pouvez également effectuer des tests basés sur les données.
e? RSpec? Non, je n'ai pas l'impression de pouvoir l'écrire parce que cela m'est trop difficile à comprendre. Qu'est-ce que «it»?
Recommended Posts