Cette tâche consiste à générer le chemin le plus court vers un fichier, après l'expansion globale.
Qu'est-ce que l'écaillage de coquille? Dans la plupart des shells, vous pouvez utiliser le *
personnage dans un chemin pour représenter n'importe quel personnage à la position. Par exemple, si le répertoire foo
contient des fichiers bar
baz
et asdf
, alors foo/b*
sera développé en foo/bar foo/baz
.
Maintenant, disons que le répertoire courant contient un fichier appelé ihavealongname
et rien d'autre. Si je veux faire référence à ce fichier, je peux taper *
, qui ne représentera que ce fichier, plutôt que de taper le nom complet.
Si le répertoire contient également un fichier appelé ialsohavealongname
, je ne peux pas le faire *
, car il correspondra aux deux fichiers. Le je dois faire, au moins, ih*
.
Le *
modèle fonctionne également pour faire correspondre les répertoires au-dessus du fichier que je recherche. S'il n'y a que deux répertoires foo
et bar
, mais foo
ne contient qu'un fichier baz
et bar
contient un fichier asdf
, je peux correspondre foo/baz
avec */baz
. Ou, encore plus de façon concise, */b*
. Si bar
était vide, */*
fonctionnerait.
Votre tâche: étant donné un tableau de chaînes de chemins qui représentent le "répertoire en cours" et un seul chemin cible, sortez la chaîne la plus courte possible qui se développerait uniquement sur ce chemin cible après avoir développé * s.
Le chemin cible peut être considéré comme sa propre chaîne, comme un index dans le tableau de chemins, comme le premier élément du tableau de chemins transmis ou d'une autre manière pratique qui ne soit pas codée en dur. Demandez dans les commentaires en cas de doute.
Le chemin cible est garanti d'être présent dans le "répertoire courant".
Vous pouvez supposer que tous les chemins ne contiennent que des ASCII alphanumériques (et /
s). Vous pouvez prendre comme chemins d'entrée qui sont enracinés (commencez par /
) ou relatifs (ne commencez pas par /
).
S'il existe plusieurs possibilités également courtes, renvoyez-en une ou toutes.
C'est le code-golf , le moins d'octets gagne!
Cas de test , merci à Kevin Cruijssen .
la source
*
,?
,[
etc? Il serait peut-être plus simple de simplement indiquer que les noms de fichiers et de répertoires sont alphanumériques*
et exécuterais perlglob
pour obtenir tous les noms de fichiers qui peuvent être pertinents (par exemple,foo/bar/baz
devient*/*/*
). Après cela, cela devient un défi de traitement de chaîne. Et ce défi est déjà assez difficile. Je pense que ce défi serait plus propre car "étant donné une liste de/
chemins relatifs alphanumériques (et ), trouvez le plus court glob qui ne correspond qu'à ce chemin cible existanta*f
pour sélectionner àazzf
partirazzf
,azzg
,bzzf
. Prolongez à volonté versa*b*c
etc.Réponses:
Perl 5 ,
136107102 102 octetsComprend
+2
pourn0
Donner la liste des fichiers sur STDIN. Le premier est supposé être le fichier cible
Juste le code sans rendre les sauts de ligne littéraux:
Se bloque intentionnellement après l'impression de la solution.
Semble toujours trop long (l'utilisation de
$a
et1/0
sont très maladroits), mais c'est un début et devrait être raisonnablement efficace.Essayez-le en ligne!
Comment ça fonctionne
Le programme crée des globes candidats en les faisant croître de l'arrière vers l'avant en commençant par la chaîne vide. Il le fait d'une première manière large, donc d' abord globs de longueur 0 sont jugés (uniquement ``), puis la longueur 1 (comme
t
,i
,*
), la longueur suivante 2 (commefb
,i*
,*g
,**
), la longueur suivante 3 et ainsi de suite jusqu'à ce qu'un glob est trouvé qui ne correspond qu'au premier chemin. Ce sera alors le glob le plus court qui résout le problème (d'autres de même longueur peuvent exister).Les globes de longueur
n+1
sont générés à partir des globes de longueur enn
faisant précéder chaque caractère de la liste des chemins et également*
devant chaque glob de longueurn
. Ainsi , par exemple , longueur 3 glob*i*
contribuera longueur 4 globsf*i*
,o*i*
,o*i*
,/*i*
,b*i*
...s*i*
,t*i*
et enfin**i*
. Notez que chaque caractère de la liste des chemins d'entrée est ajouté au début même s'il apparaît plusieurs fois ou n'a aucun sens car cela conduit à quelque chose qui ne peut jamais correspondre.Faire cela naïvement conduirait à une explosion combinatoire. C'est pourquoi chaque glob candidat est évalué pour son utilité en déterminant à quels points des chemins il pourrait correspondre si le glob était utilisé à la fin d'un glob complet. Je le fais en insérant un
;
à chaque endroit où un match est possible. Par exemple pour le globt*
j'obtiendrai la chaîne:Cela représente le «pouvoir distinctif» du globe. Chaque glob qui a exactement le même pouvoir de distinction est également bon. Si vous les remplacez les uns par les autres à la fin d'un glob complet, ils correspondront tous exactement aux mêmes chemins. Vous pouvez donc tout aussi bien utiliser le plus court.
Donc, lorsque l'on considère la longueur des
n
globes, je regarde d'abord son pouvoir distinctif. S'il a été vu auparavant, il y a eu un autre globule de longueurn
ou plus court qui a déjà été considéré et étendu, donc ce glob est inutile et est élagué. Cela permettra par exemple de se débarrasser des candidats comme**i*
puisque le même pouvoir de distinction aura déjà été perçu comme*i*
. Il élague également les candidats impossibles,f*i*
car la chaîne distinctive n'aura pas;
et juste être la liste originale des chemins. Seul le tout premier globe impossible sera accepté, tous les autres seront considérés comme ayant le même pouvoir distinctif et seront élagués. Et même cette première ne sera pas vraiment développée car toutes les extensions sont toujours impossibles et seront élaguées lorsqu'elles seront prises en compte. Simulairementin*
sera élagué pari*
etc.Ce qui précède conduit à une taille très agressive et le programme est donc capable de traiter des cas complexes en très peu de temps. Une inefficacité majeure est cependant qu'elle préfixe les globes candidats avec tous les caractères possibles, pas seulement ceux juste avant une partie
;
dans le chemin cible de la chaîne de distinction. Tous les personnages ajoutés qui ne sont pas devant un;
ne posent aucun problème car ils conduisent à un glob impossible qui sera élagué quand il sera considéré, mais cela laisse toujours les personnages juste avant;
dans les autres chemins. Donc, à la fin, le programme crée également des globes qui pourront correspondre à n'importe quelle combinaison des chemins donnés. Il n'a aucune idée qu'il devrait se concentrer sur le premier chemin.Considérez maintenant une solution au problème. Dans l'exemple donné, cela pourrait être
*/*er/t
. Cela donne la chaîne distinctive suivante:Je reconnais une solution en ayant un
;
à la première position (donc il correspond au premier chemin) et sans avoir;
au début d'un autre chemin (donc les autres ne correspondent pas)Avec l'algorithme expliqué, j'arrive maintenant au programme réel:
Les globs candidats seront dans un tableau
@a
que je boucle en utilisant une variable$a
qui contient le glob actuellement considéré. Au lieu de*
dans le glob, je vais cependant utiliser\w*
donc$a
est en fait un regex au lieu d'un glob. Je vais abuser d'une étrangeté de la boucle perl pour que vous puissiez ajouter des éléments au tableau en boucle pendant que la boucle est en cours d'exécution et ces nouveaux éléments seront récupérés dans la boucle. Puisque lors de la génération desn+1
globes de longueur, tous les globs de longueurn
sont déjà sur le tableau,@a
c'est la largeur en premier.En raison de l'
-n0
option (boucle implicite sur toute l'entrée), la liste des chemins est dans$_
une grande chaîne avec chaque chemin terminé par une nouvelle ligneÀ l'intérieur,
{ }
nous avons:Oups, je viens de détruire
$_
et j'en aurai besoin pour la prochaine boucle. Enveloppez donc le code de travail réel à l'intérieurCela correspond à la chaîne vide au début de
$_
et vous permet d'exécuter du code pour déterminer par quoi il sera remplacé. Si je m'assure que ce code s'évalue à la chaîne vide$_
restera à la fin inchangé même si je change$_
pendantcode
.Pour en revenir juste après avoir remplacé
$_
par la chaîne distinctive:C'est comme:
//
en perl est'defined or
. C'est comme un court-circuitor
où le deuxième argument n'est évalué que si le premier l'estundef
. Et il peut être combiné avec une mission comme+=
dans certaines autres langues. Donc, s'ils saisissent le$_
hachage%seen
estundef
(ce qui est ce que vous obtenez lorsque vous accédez à un élément non existant), alors exécutez l'expression et affectez-la comme valeur à la clé$_
. Donc, si je m'assure deexpression
ne pas retourner,undef
cela signifie essentiellement "évaluer l'expression si et seulement si c'est la première fois que nous voyons cette chaîne distinctive particulière". Et parce qu'il$_
est garanti de contenir un,\n
il est en fait sûr d'abuser du hachage global perl pour stocker les chaînes distinctives, donc$$_
au lieu de$seen{$_}
Pour le
expression
j'utilise:Fondamentalement, "pour chaque caractère (sauf le saut de ligne) dans la chaîne de distinction, et
*
ajoutez-le également au glob actuel et poussez-le sur le tableau des globs candidats". Execpt que j'utilise\w*
pour*
obtenir une expression rationnelle valide (je pourrais utiliser''
au lieu de""
pour me débarrasser d'une barre oblique inverse mais je ne pouvais pas exécuter mon code à partir de la ligne de commande). Notez que cela récupère également les;
et les ajoute aux globs candidats, mais lors de leur test ultérieur sur le restauré$_
qui n'a pas,;
ce sera à nouveau un glob impossible et être élagué.Notez que
/^;/>/\n;/
la valeur est équivalente à la chaîne vide dans le cas où une solution n'a pas encore été trouvée, donc cela fonctionnera comme une chaîne de remplacement vide et sera$_
restauréla source
-E
active le dernier niveau de langue. Vous avez besoin d'au moins perl5.10.0
pour pouvoir l'utilisersay
. Donc, mettezuse 5.10.0;
dans la section d'en-tête et cela fonctionnera. Options pour définir le niveau de langue comme gratuit de toute façon même si vous ne pouvez pas le faire en utilisant également-E
. En fait, toutes les options comptent comme gratuites de nos jours (donc je n'ai même pas besoin de comptern0
), mais je considère cela trop indulgent pour perl1/
solution est valide! Je dois aussi m'en souvenir ...Java 10,
854824796738728703688655652647624 octetsQuel gâchis .. Ce n'est certainement pas un défi facile en Java.
Peut certainement être joué par quelques centaines d'octets, mais je suis juste content que cela fonctionne enfin maintenant.Je te l'avais dit. :)-5 octets grâce à @ceilingcat .
-23 octets passant de Java 8 à Java 10
Entrée sous forme de tableau de chaînes de chemins de fichiers (avec des répertoires en tant qu'éléments séparés et tous les éléments contenant un interligne
/
), et une chaîne avec chemin de fichier d'entrée à rechercher.Explication:
Essayez-le en ligne. (Les cas de test avec
ialsohavealongname
/ihavealongnameaswell
sont légèrement réduits en longueur ets.add(x.replaceAll("~+","\\*"));
ont été remplacés par{s.remove(x);s.add(x.replaceAll("~+","\\*"));}
pour fonctionner en 5-10 secondes sur TIO, au lieu de s'arrêter après 60+ secondes.)Explication générale supplémentaire:
Exemple: Prenons
/foo, /foo/bar, /foo/barber, /foo/bar/test, /foo/barber/test, /foo/barber/testing, /foo/barber/coding, /foo/test
comme chemins de fichier donnés etfoo/bar/test
comme chemin de fichier d'entrée pour grop.1) Je commence par diviser l'entrée du chemin de fichier par
/
et génère tous les groppings de fichier de ces mots séparés:2) Je génère ensuite toutes les permutations avec ces mots dans le même ordre (en appliquant de nouveau
/
entre et à l'avant):3) Ensuite, je fais une boucle sur les éléments de cette liste ci-dessus et valide si elle ne correspond qu'à un seul chemin de fichier dans le tableau d'entrée de chemins de fichier. (Je fais cela en vérifiant deux choses: la quantité de barres obliques est-elle la même et correspond-elle à l'expression régulière où tout
*
est remplacé par.*
?)Si c'est le cas: gardez la (première) plus courte, que nous retournons à la fin.
la source
>>>
? Je sais que>>
c'est le décalage à droite au niveau du bit.>>>
agit de la même manière que>>
. Mais pour les entiers négatifs, il change le bit de parité à 0 (vous pouvez voir quelques exemples ici à la section " >> vs >>> " ).-1>>>1
est juste une variante plus courte deInteger.MAX_VALUE
(et le1<<31
seraitInteger.MIN_VALUE
).