Génère toutes les chaînes d'accolade de longueur n

16

Une chaîne d'accolade est définie comme une chaîne composée des caractères *()[]dans lesquels les accolades correspondent correctement:

[brace-string] ::= [unit] || [unit] [brace-string]
[unit]         ::= "" || "*" || "(" [brace-string] ")" || "[" [brace-string] "]"

Ceci est une chaîne d'accolade valide:

((())***[]**)****[(())*]*

Mais ce ne sont pas:

)(
**(**[*](**)
**([*)]**

Votre tâche consiste à écrire un programme (ou une fonction) qui, étant donné un entier positif n, prend un nombre en entrée et génère (ou renvoie) toutes les chaînes d'accolade valides de longueur n.

Caractéristiques

  • Vous pouvez sortir les chaînes dans n'importe quel ordre.
  • Vous pouvez produire une liste ou une chaîne séparée par un caractère différent.
  • Votre programme doit gérer correctement 0. Il existe 1 chaîne d'accolade possible de longueur 0, qui est la chaîne vide "".
  • Il s'agit de , donc la réponse valide la plus courte - mesurée en octets - l'emporte.

Cas de test

0. 
1. *
2. ** () []
3. *** ()* []* (*) [*] *() *[]
4. **** ()** []** (*)* [*]* (**) **() **[] *(*) *[*] (()) ()() ()[] ([]) [**] [()] [[]] []() [][] *()* *[]*
Esolanging Fruit
la source
3
Le nombre d'entrées dans la sortie est A025235
Gabriel Benamy
@GabrielBenamy Ah. Je me demandais si cela avait déjà été examiné. Intéressant.
Esolanging Fruit
2
Quelle est la condition gagnante? J'assume le programme le plus court (code golf).
Zgarb
En relation.
Martin Ender
1
Puisque tout le monde suppose que c'est du golf de code, je marquerai le défi en conséquence (car cela rendrait autrement toutes les réponses existantes quelque peu inutiles). Si vous vouliez un critère de gain différent, vous pourriez envisager de publier un nouveau défi.
Martin Ender

Réponses:

3

Gelée, 29 octets

-3 octets grâce à @JonathanAllan

Veuillez m'alerter s'il y a des problèmes / bugs / erreurs ou octets que je peux supprimer!

“[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐLÐḟ

Essayez-le en ligne!

La ou les solutions précédentes que j'avais:

“[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€Tị
“[(*)]”ṗµ¹ḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€Tị
“[(*)]”ṗµ¹ḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€×Jḟ0ị
“[(*)]”x⁸ṗ⁸Qµ¹ḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€×Jḟ0ị
“[(*)]”x⁸ṗ⁸Qµ¹µḟ”*œṣ⁾()Fœṣ⁾[]FµÐL€Ṇ€×Jḟ0ị
“[(*)]”x⁸ṗ⁸Qµ¹µḟ”*œṣ⁾()Fœṣ⁾[]FµÐLµ€Ṇ€×Jḟ0ị

Explication (ma meilleure tentative de description):

Input n
“[(*)]”ṗ-All strings composed of "[(*)]" of length n
µḟ”*    -Filter out all occurences of "*"
œṣ⁾()   -Split at all occurences of "()"
F       -Flatten
œṣ⁾[]   -Split at all occurences of "[]"
F       -Flatten
µÐL     -Repeat that operation until it gives a duplicate result
Ðḟ      -Filter
Zacharý
la source
Vous pouvez enregistrer trois octets en utilisant le filtrage ( “[(*)]”ṗµḟ”*œṣ⁾()Fœṣ⁾[]FµÐLÐḟ)
Jonathan Allan
15

Prolog, 69 octets

s-->[];e,s.
e-->"*";"(",s,")";"[",s,"]".
b(N,A):-length(A,N),s(A,[]).

L'une des propriétés les plus intéressantes de Prolog est que, dans de nombreux cas, il est capable d'exécuter un programme à l'envers; par exemple, au lieu de tester pour voir si quelque chose est vrai, vous pouvez générer toutes les solutions pour lesquelles c'est vrai, et au lieu de vérifier la longueur d'une chaîne, vous pouvez générer toutes les chaînes avec une longueur donnée. (Une autre belle propriété de Prolog est qu'il nécessite un espace après la fin de chaque définition de prédicat, et une nouvelle ligne peut être insérée à moindre coût qu'un espace; ainsi, même les programmes joués au golf sont souvent assez lisibles.)

Ce qui précède définit un prédicat (l'équivalent d'une fonction) bqui teste pour voir si une chaîne a une longueur donnée et est une "chaîne d'accolade" telle que définie dans la question. Plus précisément, il le fait via le support grammatic / regex / pattern-match de Prolog qui donne un peu de sucre court pour définir ce type d'expression (apparemment, c'est standard / portable, mais je ne le savais pas lors de l'écriture de la réponse, et donc supposait que la réponse ne fonctionnerait que sur une seule implémentation de Prolog; il semble cependant qu'elle fonctionne sur chaque implémentation conforme aux normes). Le programme peut être traduit assez directement en anglais; les deux premières lignes disent "un s est une chaîne vide, ou un e suivi d'un s ; un eest un astérisque, ou un s entre parenthèses, ou un s entre crochets ". La troisième ligne peut être interprétée comme" Le b de N peut être A si A est une liste de longueur N et A est un s suivi d'un null chaîne."

Je pris quelques précautions à écrire s(et donc b) afin qu'ils correspondent exactement d' une manière chaque « chaîne de renfort » ( ce qui est la raison pour laquelle les deux set edoivent exister, plutôt que de les regrouper en un seul prédicat). Cela les rend tous deux entièrement réversibles; ainsi bpeut être utilisé pour générer toutes les "chaînes d'accolade" d'une longueur donnée, en plus de tester si une chaîne est une chaîne d'accolade d'une longueur donnée (elle peut également être utilisée dans un troisième sens, pour déterminer la longueur d'une accolade , mais c'est presque certainement son mode de fonctionnement le moins utile). L'implémentation est récursive, par exemple pour générer un s , le code générera tous les e s possibles qui ne sont pas plus longs que la longueur requise de la sortie, et ajoutera tous les s possibless qui leur correspondent dans l'espace restant; parce que j'ai spécifié la longueur de l'argument à l'avance (dans b ), le moteur Prolog sait qu'il ne peut pas générer de sortie plus longue que la longueur donnée, ce qui permet à la récursivité de se terminer.

Voici un exemple du programme en fonctionnement:

| ?- b(4,A),format("~s ",[A]),fail.
**** **() **[] *()* *(*) *[]* *[*] ()** ()() ()[] (*)* (**) (()) ([]) []** []() [][] [*]* [**] [()] [[]]

la source
il semble qu'il devrait y avoir un certain coût pour la syntaxe requise pour spécifier si vous voulez exécuter le programme "en avant" ou "en arrière". perl paie 1 octet pour chaque bit de ce genre de chose
Sparr
Eh bien, vous pouvez établir une règle selon laquelle les arguments à la fin sont toujours la valeur de retour, puis inverser l'ordre des arguments pour spécifier la direction dans laquelle vous exécutez le programme. Il est assez courant pour les langues de golf de comprendre ce qu'elles devraient faire en partie en vérifiant si elles ont reçu une contribution, et c'est un principe comparable. En général, cependant, il est difficile de faire des règles qui s'appliquent à toutes les langues possibles; exécuter des buildins comme lengthet dans les appenddeux sens est une partie fondamentale du langage, et les fonctions utilisateur font souvent la même chose.
Oh, hmm. J'ai supposé qu'il y avait une indication dans votre exemple qui a déclenché le comportement en question.
Sparr
Non, c'est entièrement dû aux arguments donnés. Dans le programme ci-dessus, j'écris length(A,N); si Nest donné et Ane l'est pas (ce qui se produira si le prédicat est utilisé de la manière demandée dans le programme), lengthgénérera une liste Acomposée d' Néléments inconnus. L'utilisation lengthpour mesurer la longueur d'une liste est probablement plus couramment utilisée (bien que son utilisation "en arrière" soit assez courante dans la programmation Prolog). La plupart des prédicats finissent par fonctionner de la même manière (la seule raison pour laquelle ils ne le sont pas si tenter de les inverser construirait une boucle infinie, ce qui est assez courant).
1
@ ais523 -->et les DCG en général sont ISO Prolog standard .
Fatalize
5

Haskell, 101 94 octets

7 octets enregistrés par Zgarb!

b 0=[""]
b n=[x++y|k<-[1..n],x<-u k,y<-b$n-k]
u 1=["*"]
u n=[a:s++b|s<-b$n-2,a:b<-["()","[]"]]

Presque simple, suivant la définition, mais avec le ""cas déplacé.

Utilisation:

*Main> map b [0..3]
[[""],["*"],["**","()","[]"],["***","*()","*[]","()*","[]*","(*)","[*]"]]
*Main> length $ b 10
21595

(Le deuxième calcul prend moins d'une seconde sur une machine lente.)

J'aimerais également partager le résultat d'une autre approche que j'ai imaginée en pensant à générer des fonctions. Il définit une liste b de listes de chaînes qui b!!ncontient toutes les chaînes d'accolade de longueur n. De même, u!!ncontient tous les atomes de taille n-1. Une bonne chose est que le code n'utilise aucun chiffre. Il n'est pas complètement joué au golf : uil ipourrait être aligné, et il manque certainement quelques autres opportunités de golf. Malheureusement, il ne semble pas pouvoir être raccourci par rapport à la première version, mais il calcule length $ b !! 10encore plus rapidement.

b=[""]:b%u
u=["*"]:map i b
i=concatMap(\s->['(':s++")",'[':s++"]"])
(b:c)%f=zipWith(++)[[x++y|x<-b,y<-e]|e<-f]([]:c%f)
Christian Sievers
la source
Enregistrez deux octets avec b$n-ket b$n-2. En outre, sur la dernière ligne, vous pouvez faire a:b<-["()","[]"]et revenir a:s++b.
Zgarb
Oh, je voulais utiliser ["()","[]"]mais je ne voyais pas comment améliorer la taille du code avec. Merci!
Christian Sievers
4

Mathematica, 116 octets

#<>""&/@Select[Characters@"*([)]"~Tuples~#,(#/."*"->Nothing//.{a___,"(",")",b___}|{a___,"[","]",b___}:>{a,b})=={}&]&

Explication

Characters@"*([)]"

Trouvez les caractères de la chaîne "*([)]"en donnant le List {"*", "(", "[", ")", "]"}.

... ~Tuples~#

Trouvez les tuples de la liste ci-dessus avec la longueur n.

(#/."*"->Nothing//.{a___,"(",")",b___}|{a___,"[","]",b___}:>{a,b})=={}&

Fonction booléenne sans nom pour déterminer si le tuple est équilibré:

#/."*"->Nothing

Supprimer tout "*"dans l'entrée.

... //.{a___,"(",")",b___}|{a___,"[","]",b___}:>{a,b}

Supprimez à plusieurs reprises toutes les occurrences consécutives de "("et ")"ou "["et "]"jusqu'à ce que l'entrée ne change pas.

... =={}

Vérifiez si le résultat est vide List.

Select[ ... , ... ]

Trouvez les tuples qui donnent Truelorsque la fonction booléenne est appliquée.

#<>""&/@

Convertissez chacun Listdes caractères en Strings.

JungHwan Min
la source
2
De façon quelque peu inattendue, {x=a___,"(",")",y=b___}|{x,"[","]",y}semble fonctionner.
Martin Ender
4

Python 2, 128 octets

n=input()
for i in range(5**n):
 try:s=','.join('  "00([*])00"  '[i/5**j%5::5]for j in range(n));eval(s);print s[1::4]
 except:1

Vissez des expressions rationnelles récursives - nous utilisons l'analyseur de Python! Afin de vérifier qu'il s'agit, par exemple, d' *(**[])*une chaîne d'accolade, nous procédons comme suit:

  1. Créez une chaîne comme "*", (0,"*","*", [0,0] ,0) ,"*", où chaque deuxième caractère sur quatre est un caractère des chaînes d'accolade, et les caractères restants sont collés pour en faire une expression Python potentielle.

  2. eval il.

  3. Si cela ne génère pas d'erreur, imprimez s[1::4](les caractères d'accolade).

Les caractères de collage sont choisis de sorte que la chaîne que je crée est une expression Python valide si et seulement si la prise d'un caractère sur deux sur quatre donne une chaîne d'accolade valide.

Lynn
la source
2

PHP, 149 octets

for(;$argv[1]--;$l=$c,$c=[])foreach($l?:['']as$s)for($n=5;$n--;)$c[]=$s.'*()[]'[$n];echo join(' ',preg_grep('/^((\*|\[(?1)]|\((?1)\))(?1)?|)$/',$l));

Utilise le bon vieux générer toute la méthode possible puis filtrer. Utilisez comme:

php -r "for(;$argv[1]--;$l=$c,$c=[])foreach($l?:['']as$s)for($n=5;$n--;)$c[]=$s.'*()[]'[$n];echo join(' ',preg_grep('/^((\*|\[(?1)]|\((?1)\))(?1)?|)$/',$l));" 4
user59178
la source
1

Python, 134 octets

from itertools import*
lambda n:[x for x in map(''.join,product('*()[]',repeat=n))if''==eval("x"+".replace('%s','')"*3%('*',(),[])*n)]

repl.it

Fonction sans nom qui renvoie une liste de chaînes de longueur valides n.
Formes toute la longueur ntuples des personnages *()[], ce qui les rejoint en chaînes en utilisant map(''.join,...)et filtres pour ceux qui ont équilibré entre parenthèses en supprimant les « paires » "*", "()"et "[]"à son tour nfois et vérifier que le résultat est une chaîne vide ( ntemps est surpuissant, en particulier pour "*"mais est golfeur).

Jonathan Allan
la source
1

Rétine , 78 octets

Le nombre d'octets suppose un codage ISO 8859-1.

.+
$*
+%1`1
*$'¶$`($'¶$`)$'¶$`[$'¶$`]
%(`^
$';
)+`(\[]|\(\)|\*)(?=.*;)|^;

A`;

Essayez-le en ligne!

Explication

Je génère toutes les chaînes possibles de longueur 5, puis je filtre celles qui ne sont pas valides.

.+
$*

Cela convertit l'entrée en unaire, en utilisant 1 comme chiffre.

+%1`1
*$'¶$`($'¶$`)$'¶$`[$'¶$`]

Cela +remplace à plusieurs reprises ( ) le premier (1 ) un dans chaque ligne ( %) de telle manière qu'il fait cinq copies de la ligne, une pour chaque caractère possible. Cela se fait en utilisant les substitutions de préfixe et de suffixe, $`et $'pour construire le reste de chaque ligne.

Cette boucle s'arrête lorsqu'il n'y a plus de 1 à remplacer. À ce stade, nous avons toutes les chaînes de longueur possiblesN , une sur chaque ligne.

%(`^
$';
)+`(\[]|\(\)|\*)(?=.*;)|^;

Ces deux étapes sont exécutées séparément pour chaque ligne ( %). La première étape duplique simplement la ligne, avec un ;pour séparer les deux copies.

La deuxième étape est une autre boucle ( +), qui supprime à plusieurs reprises [], ()ou *de la première copie de la chaîne, ou supprime un point-virgule au début de la ligne (ce qui n'est possible qu'après que la chaîne a complètement disparu).

A`;

Les chaînes valides sont celles qui n'ont plus de point-virgule devant elles, donc nous rejetons simplement toutes les lignes ( A) qui contiennent un point-virgule.

Martin Ender
la source
J'ai essayé en ligne avec l'entrée 5: ok. Avec l'entrée 6, j'ai une page d'erreur
edc65
@ edc65 Fonctionne pour moi, mais bien sûr cette approche n'est pas exactement efficace, donc cela prend quelques secondes. Quel genre de page d'erreur voulez-vous dire?
Martin Ender
Entrée 5: réponse en 3 sec. Entrée 6: après 7 secondes, à l'intérieur de la boîte de sortie, j'obtiens la source html de ce qui est probablement une page d'erreur de mon proxy. Si c'est un délai d'attente, c'est un délai très court ... J'essayais d'obtenir un bon cas de test pour l'entrée 6, car ma réponse semble correcte jusqu'à l'entrée 5, mais incorrecte pour 6 ou plus
edc65
@ edc65 Cela prend définitivement plus de 7 secondes et le délai d'expiration de TIO est d'une minute. Je n'ai jamais vu l'erreur que vous décrivez, cela pourrait valoir la peine de le mentionner dans le chat TIO (ou si vous préférez sur gitter ou GitHub ). En ce qui concerne la sortie de référence, voici ce que j'obtiens pour l'entrée 6: pastebin.com/WmmPPmrc (l'entrée 7 prend plus d'une minute.)
Martin Ender
1

Python 3.5, 146 octets

import re;from itertools import*;lambda f:{i for i in map(''.join,permutations("[()]*"*f,f))if re.fullmatch("(\**\[\**\]\**|\**\(\**\)\**)*|\**",i)}

Très longue par rapport aux autres réponses, mais la plus courte que j'ai pu trouver actuellement. Elle se présente sous la forme d'une fonction lambda anonyme et doit donc être appelée au format

print(<Function Name>(<Integer>))

Sort un ensemble Python de non ordonné chaînes représentant toutes les chaînes d'accolade possibles de la longueur d'entrée.

Par exemple, en supposant que la fonction ci-dessus est nommée G, l'appel G(3)entraînerait la sortie suivante:

{'[*]', '*()', '*[]', '(*)', '***', '[]*', '()*'}

Essayez-le en ligne! (Ideone)


Cependant, si, comme moi, vous n'êtes pas vraiment fan de simplifier les choses en utilisant Encastrements, alors voici ma originale réponse n'utilisant des bibliothèques externes pour trouver des permutations, et se situe actuellement à un énorme 288 237 octets :

import re;D=lambda f:f and"for %s in range(%d)"%(chr(64+f),5)+D(f-1)or'';lambda g:[i for i in eval('["".join(('+''.join('"[()]*"['+chr(o)+'],'for o in range(65,65+g))+'))'+D(g)+']')if re.fullmatch("(\**\[\**\]\**|\**\(\**\)\**)*|\**",i)]

Encore une fois, comme la réponse concurrente, celle-ci se présente sous la forme d'une fonction lambda et doit donc également être appelée au format

print(<Function Name>(<Integer>))

Et génère une liste Python de chaînes non triées représentant toutes les chaînes d'accolade de la longueur d'entrée. Par exemple, si le lambda devait être appelé en tant que G(3), cette fois, la sortie serait la suivante:

['*()', '(*)', '*[]', '[*]', '()*', '[]*', '***']

En outre, celui-ci est également beaucoup plus rapide que mon autre réponse, étant capable de trouver toutes les chaînes de croisillon de longueur 11en environ 115 secondes , celles de longueur 10en environ 19 secondes , celles de longueur 9en environ 4 secondes et celles de longueur 8en environ 0,73 secondes sur ma machine, alors que ma réponse concurrente prend beaucoup plus de 115 secondes pour une entrée de6 .

Essayez-le en ligne! (Ideone)

R. Kap
la source
0

05AB1E, 23 octets

…[(*.∞sãʒ'*м„()„[]‚õ:õQ

Certaines de ces fonctionnalités peuvent avoir été implémentées après la publication de la question. Toutes les suggestions sont les bienvenues!

Essayez-le en ligne!

Comment?

…[(* - the string '[(*'
.∞ - intersected mirror, '[(*'=>'[(*)]'
s - swap the top two items, which moves the input to the top
ã - cartesian power
ʒ ...  - filter by this code:
  '*м      - remove all occurrences of '*'
  „()„[]‚  - the array ["()","[]"]
  õ        - the empty string ""
  :        - infinite replacement (this repeatedly removes "()", "[]", and "*" from the string
  õQ       - test equality with the empty string
Zacharý
la source
Je ne connais pas 05AB1E, mais ne pourrait-il pas *également être dans le tableau de suppression? Et le õQchèque pourrait-il être remplacé par quelque chose comme NON?
Esolanging Fruit
La première suggestion ne sauvera aucun octet: '*м„()„[]‚õ:vs „()„[]‚'*«õ:(non testé), car il n'y a pas de commande pour concaténer 3 valeurs AFAIK. Le second ne fonctionnera pas car il n'y a pas de NOT qui fonctionnerait comme ça sur une chaîne, AFAIK. (Où AFAIK représente "autant que je sache")
Zacharý