Vista explodida de uma string


39

Você não ama aqueles diagramas de vista explodida nos quais uma máquina ou um objeto é desmontado em suas partes menores?

insira a descrição da imagem aqui

Vamos fazer isso com uma string!

O desafio

Escreva um programa ou função que

  1. insere uma string contendo apenas caracteres ASCII imprimíveis ;
  2. disseca a string em grupos de caracteres iguais a não espaço (as "partes" da string);
  3. gera esses grupos em qualquer formato conveniente, com algum separador entre os grupos .

Por exemplo, dada a sequência

Ah, abracadabra!

a saída seria os seguintes grupos:

!
,
UMA
aaaaa
bb
c
d
h
rr

Cada grupo na saída contém caracteres iguais, com espaços removidos. Uma nova linha foi usada como separador entre grupos. Mais sobre os formatos permitidos abaixo.

Regras

A entrada deve ser uma sequência ou uma matriz de caracteres. Ele conterá apenas caracteres ASCII imprimíveis (o intervalo inclusivo do espaço ao til). Se o seu idioma não suportar isso, você poderá inserir a entrada na forma de números que representam códigos ASCII.

Você pode supor que a entrada contenha pelo menos um caractere não espacial .

A saída deve consistir em caracteres (mesmo que a entrada seja por meio de códigos ASCII). Deve haver um separador inequívoco entre os grupos , diferente de qualquer caractere não espacial que possa aparecer na entrada.

Se a saída for via retorno de função, também poderá ser uma matriz ou seqüências de caracteres, ou uma matriz de matrizes de caracteres ou estrutura semelhante. Nesse caso, a estrutura fornece a separação necessária.

Um separador entre os caracteres de cada grupo é opcional . Se houver um, a mesma regra se aplica: ele não pode ser um caractere não espacial que pode aparecer na entrada. Além disso, não pode ser o mesmo separador usado entre os grupos.

Fora isso, o formato é flexível. aqui estão alguns exemplos:

  • Os grupos podem ser cadeias separadas por novas linhas, como mostrado acima.

  • Os grupos podem ser separados por qualquer caractere não ASCII, como ¬. A saída para a entrada acima seria a string:

    !¬,¬A¬aaaaa¬bb¬c¬d¬h¬rr
    
  • Os grupos podem ser separados por n > 1 espaços (mesmo que n seja variável), com caracteres entre cada grupo separados por um único espaço:

    !  ,    A   a a a a a    b b  c       d   h  r r
    
  • A saída também pode ser uma matriz ou lista de seqüências retornadas por uma função:

    ['!', 'A', 'aaaaa', 'bb', 'c', 'd', 'h', 'rr']
    
  • Ou uma matriz de matrizes de caracteres:

    [['!'], ['A'], ['a', 'a', 'a', 'a', 'a'], ['b', 'b'], ['c'], ['d'], ['h'], ['r', 'r']]
    

Exemplos de formatos que não são permitidos, de acordo com as regras:

  • Uma vírgula não pode ser usada como separator ( !,,,A,a,a,a,a,a,b,b,c,d,h,r,r), porque a entrada pode conter vírgulas.
  • Não é aceito descartar o separador entre grupos ( !,Aaaaaabbcdhrr) ou usar o mesmo separador entre grupos e dentro de grupos ( ! , A a a a a a b b c d h r r).

Os grupos podem aparecer em qualquer ordem na saída. Por exemplo: ordem alfabética (como nos exemplos acima), ordem da primeira aparição na sequência, ... A ordem não precisa ser consistente nem determinística.

Observe que a entrada não pode conter caracteres de nova linha Ae asão caracteres diferentes (o agrupamento diferencia maiúsculas de minúsculas ).

O menor código em bytes vence.

Casos de teste

Em cada caso de teste, a primeira linha é inserida e as linhas restantes são a saída, com cada grupo em uma linha diferente.

  • Caso de teste 1:

    Ah, abracadabra!
    !
    ,
    UMA
    aaaaa
    bb
    c
    d
    h
    rr
    
  • Caso de teste 2:

    \ o / \ o / \ o /
    ///
    \\\
    ooo
    
  • Caso de teste 3:

    Um homem, um plano, um canal: Panamá!
    !
    ,,
    :
    UMA
    P
    aaaaaaaaa
    c
    ll
    milímetros
    nnnn
    p
    
  • Caso de teste 4:

    "Mostre-me como você faz esse truque, aquele que me faz gritar", disse ela
    ""
    ,
    S
    aaaaa
    cc
    dd
    eeeeeee
    hhhhhh
    ii
    kk
    mmmm
    n
    ooooo
    rr
    ssss
    tttttt
    você
    ww
    y
    

1
Se usarmos símbolos não ASCII como "¬" como separador, ele pode ser contado como 1 byte?
Leaky Nun

5
@LeakyNun n, ele vai ser contado, uma vez que corresponde, dependendo da codificação utilizada para o código fonte, como de costume
Luis Mendo

Uma nova linha após o último grupo é aceitável?
JustinM - Restabelece Monica

Uma nova linha de saída líder é aceitável?
DJMcMayhem

1
@RohanJhunjhunwala Well done! :-) Sim, várias novas linhas como separadores são boas
Luis Mendo

Respostas:


11

Geléia , 5 bytes

ḟ⁶ṢŒg

Experimente online!

Ele retorna uma matriz, só que, quando é impressa em STDOUT, o separador desaparece.

Esta é realmente uma função que pode ser chamada como tal (no Jelly, cada linha é uma função).

ḟ⁶ṢŒg
ḟ⁶      filter out spaces
  Ṣ     sort
   Œg   group

23

Python 3.5+, 77 46 44 41 bytes

lambda s:[a*s.count(a)for a in{*s}-{' '}]

Bem simples. Percorre os caracteres únicos da string convertendo-os em um conjunto (usando a descompactação iterável estendida do Python 3.5) e, em seguida, usa uma compreensão de lista para construir os diagramas explodidos contando o número de vezes que cada caractere ocorre na string str.count. Nós filtramos os espaços removendo-os do conjunto.

A ordem da saída pode variar de execução para execução; conjuntos são desordenados, portanto, a ordem na qual seus itens são processados ​​e, portanto, essa resposta é gerada, não pode ser garantida.

Esta é uma expressão lambda; para usá-lo, prefixe lambdacom f=.

Experimente no Ideone! Ideone usa Python 3.4, o que não é suficiente.

Exemplo de uso:

>>> f=lambda s:[a*s.count(a)for a in{*s}-{' '}]
>>> f('Ah, abracadabra!')
[',', 'A', 'aaaaa', 'd', '!', 'bb', 'h', 'c', 'rr']

Guardado 3 bytes graças a @shooqie!


3
Parabéns por 1k!
Luis Mendo

2
Em Python> 3.5 você pode fazer {*s}para set(s).
shooqie

11

Retina, 13 bytes

O`.
!`(\S)\1*

A classificação é muito fácil (é embutida), está separando as letras que levam 9 bytes. Experimente online!

A primeira linha Omostra todas as correspondências da expressão regular .(que é todo caractere), fornecendo-nos !,Aaaaaabbcdhrr.

Correspondência é o estágio padrão para a última linha de um programa e !faz com que ele imprima uma lista de correspondências da regex separada por avanço de linha. A regex procura por uma ou mais instâncias de um caractere não espacial em uma linha.


O que faz o ! Faz?
Downgoat


8

Perl 6 , 28 bytes

*.comb(/\S/).Bag.kv.map(*x*)

Observe que Bag como um Hash ou Set não é ordenado, portanto a ordem dos resultados não é garantida.

Explicação:

# Whatever lambda 「*」


# grab the characters
*.comb(
  # that aren't white-space characters
  /\S/
)
# ("A","h",",","a","b","r","a","c","a","d","a","b","r","a","!")


# Turn into a Bag ( weighted Set )
.Bag
# {"!"=>1,","=>1,"A"=>1,"a"=>5,"b"=>2,"c"=>1,"d"=>1,"h"=>1,"r"=>2}


# turn into a list of characters and counts
.kv
# ("!",1,",",1,"A",1,"a",5,"b",2,"c",1,"d",1,"h",1,"r",2)


# map over them 2 at a time
.map(
  # string repeat the character by the count
  * x *
)
# ("!",",","A","aaaaa","bb","c","d","h","rr")

7

Vim, 50 , 46 bytes

i <esc>:s/./&\r/g
:sor
qq:%s/\v(.)\n\1/\1\1
@qq@qD

A explicação / gif virá mais tarde.


1
Pela primeira vez, as soluções Emacs e vim são parecidas.
YSC

7

Pitão, 6

.gk-zd

Experimente aqui ou execute um conjunto de testes .

Muito simples, -zdremove espaços da entrada e .gkagrupa cada elemento restante por seu valor. Infelizmente, não encontrei uma maneira de usar variáveis ​​de preenchimento automático. Observe que a saída é mostrada como seqüências de caracteres Python, portanto, certos caracteres (leia-se barras invertidas) são escapados. Se você quiser que seja mais legível, adicione ja no início do código.


7

Haskell, 38 bytes

f s=[filter(==c)s|c<-['!'..],elem c s]

Basicamente, a solução de nimi , mas verificando explicitamente apenas as letras que aparecem na string.


6

2sable , 7 bytes

Código:

Úð-vyÃ,

Explicação:

Ú       # Uniquify the string, aabbcc would result into abc
 ð-     # Remove spaces
   vy   # For each character...
     Ã  #   Keep those in the string, e.g. 'aabbcc', 'a' would result into 'aa'
      , #   Pop and print with a newline

Usa a codificação CP-1252 . Experimente online!


3
Isso não soa como Dennis :-P
Luis Mendo

6

JavaScript (ES6), 41 bytes

s=>[...s].sort().join``.match(/(\S)\1*/g)

Isso também não causaria uma entrada " "na matriz retornada? Não tenho certeza se isso é permitido
Value Ink

@ValueInk Bah, pensei nisso quando comecei, mas prontamente esqueci. Corrigido agora.
Neil

Umm, como está join()sendo chamado com esses backkticks duplos?
Tejas Kale

1
@TejasKale Essa é uma string de modelo ES6. Quando você prefixa um método a uma sequência de modelos, ele passa o modelo como uma matriz para o método, portanto, nesse caso, acaba chamando .join(['']). joinem seguida, converte isso na string (vazia) e a usa para unir os elementos da matriz. Nem todos os métodos convertem seus parâmetros em string, mas essa técnica é útil naqueles que o fazem.
Neil


5

Haskell, 40 bytes

f x=[v:w|d<-['!'..],v:w<-[filter(==d)x]]

Exemplo de uso: f "Ah, abracadabra!"-> ["!",",","A","aaaaa","bb","c","d","h","rr"].

O padrão v:wcorresponde apenas à lista com pelo menos um elemento, portanto, todos os caracteres que não estão na entrada são ignorados.

Também 40 bytes:

import Data.List
group.sort.filter(>' ')

@ThreeFx: Mas groupé Data.Listtambém. Enfim, acho que essa sintaxe é ghciapenas e precisa do REPL, portanto é uma linguagem própria . Eu quero ficar com o Haskell padrão.
N

4

Ruby, 41 + 1 = 42 bytes

+1 byte para -nsinalizador.

gsub(/(\S)(?!.*\1)/){puts$1*$_.count($1)}

Aceita stdin, por exemplo:

$ echo 'Ah, abracadabra!' | ruby -ne 'gsub(/(\S)(?!.*\1)/){puts$1*$_.count($1)}'
A
h
,
c
d
bb
rr
aaaaa
!

4

C # 125 98 bytes

using System.Linq;s=>s.GroupBy(c=>c).Where(g=>g.Key!=' ').Select(g=>new string(g.Key,g.Count())));

Explicação

//Using anonymous function to remove the need for a full signature 
//And also allow the implicit return of an IEnumerable
s =>

    //Create the groupings
    s.GroupBy(c => c)

    //Remove spaces
    .Where(g=> g.Key!=' ')

    //Generate a new string using the grouping key (the character) and repeating it the correct number of times
    .Select(g => new string(g.Key, g.Count()));
  • Obrigado a @TheLethalCoder, que sugeriu o uso de uma função anônima, que também me permitiu remover o ToArray chamada e retornar implicitamente apenas um IEnumerable que salva coletivamente 27 bytes

Você pode economizar 18 bytes (se eu contei corretamente), compilando-o a um Func<string, string[]>ou sejas=>s.GroupBy....
TheLethalCoder

@TheLethalCoder você tem certeza de que é aceitável no lugar de uma função, eu sempre fui cauteloso com isso, porque adiciona um pouco de clichê extra para poder executá-lo, e com o argumento de exigir que o Linq o use parece ... bem errado.
JustinM - Restabelece Monica

Heres um exemplo recente, onde eu faço isso ... codegolf.stackexchange.com/a/91075/38550 ele vai remover todo o seu clichê, desde que as funções são permitidos
TheLethalCoder

@TheLethalCoder OK, isso é bom o suficiente para mim. :) Também me permitiu remover a chamada do ToArray #
JustinM - Restabelecer Monica

4

R, 198 189 96 95 bytes

for(i in unique(a<-strsplit(gsub(" ","",readline()),"")[[1]]))cat(rep(i,sum(a==i)),"\n",sep="")

Ungolfed:

a<-strsplit(gsub(" ","",readline()),"")[[1]] #Takes the input from the console

for(i in unique(a)) #loop over unique characters found in variable a

cat(rep(i,sum(a==i)),"\n",sep="") # print that character n times, where n was the number of times it appeared

Atualmente, esta solução não está funcionando totalmente quando \está envolvida.
Agora é!

Obrigado muito que você @JDL para jogar golfe fora 102 bytes!


@JDL: Por favor, sugira edições nos comentários. Suas mudanças são realmente interessantes, mas é meio rude mudar o código de outra pessoa assim.
Frédéric

1
desculpas por isso, mas eu não tinha 50 reputação na época e não podia fazer comentários. Fará no futuro embora!
JDL 26/08

@JDL: Justo!
Frédéric

Tente atribuir a variável dentro de uma função: for(i in unique(a=strsplit(gsub(" ","",readline()),"")[[1]]))cat(rep(i,sum(a==i)),"\n",sep="")- economiza 2 bytes.
Andreï Kostyrka

@ AndreïKostyrka: Ele não salva bytes neste formato porque você deve colocar a parte a = strsplit (...) entre colchetes: basicamente faz uma diferença de -2 + 2. No entanto, o uso <-economizará 1 byte!
Frédéric

4

Rápido, 105 91 bytes

Obrigado a @NobodyNada por 14 bytes :)

Sim, sou bem novo no Swift ...

func f(a:[Character]){for c in Set(a){for d in a{if c==d && c != " "{print(c)}}
print("")}}

Os caracteres dentro de um grupo são separados por uma única nova linha. Os grupos são separados por duas novas linhas.


Você pode salvar 13 bytes usando a entrada como a em [Character]vez de a String, uma vez que as regras dizem "A entrada deve ser uma string ou uma matriz de caracteres". Além disso, print("")pode ser substituído por apenasprint() .
NobodyNada - Reinstate Monica

@NobodyNada printsem argumentos não funcionou por algum motivo, mas a [Character]sugestão foi sólida. Obrigado!
jrich

3

Oitava , 61 bytes

@(x)mat2cell(y=strtrim(sort(x)),1,diff(find([1 diff(+y) 1])))

Essa é uma função anômala que recebe uma string como entrada e gera um array de células de strings.

Experimente a Ideone .

Como funciona

  • sortclassifica a sequência de entrada. Em particular, os espaços estarão no início.
  • strtrim remove espaços à esquerda.
  • diff(+y) calcula diferenças consecutivas entre caracteres (para detectar limites do grupo) ...
  • ... diff(find([1 diff(+y) 1])fornece um vetor de tamanhos de grupos.
  • mat2cell em seguida, divide a sequência classificada em pedaços com esses tamanhos.

3

Mathematica, 36 bytes

Funções internas Gathere Charactersfaz a maior parte do trabalho aqui.

Gather@Select[Characters@#,#!=" "&]&

3

> <> , 49 bytes

i:0(?v
84}0~/&{!*
v!?: <}/?=&:&:<
>&1+&}aol1-?!;^

Muito desperdício na produção, mas presumo que ainda seja permitido, dada a clareza das regras

Explicação:

i:0(?v           Collects text from input
84}0~/&{!*       adds 32 (first ascii starting at space) to register and 0 to stack
v!?: <}/?=&:&:<  checks all characters to the current register, if equal:
       o         prints the character and continues looping
>&1+&}aol1-?!;^  when all characters are checked, adds 1 to register, prints a newline,
                 checks the stack length to halt the program if 0, and starts looping again

encaixe algumas coisas bem apertadas, mesmo usando saltos para contornar algumas funções, para que eu possa executar o ponteiro verticalmente.

Basicamente, isso coloca cada caractere ASCII em sua própria nova linha e, se nenhum desses caracteres existir, a linha ficará em branco

Experimente online

Edit: eu estava errado, havia um erro no código o que faria com que ele nunca fosse concluído se houvesse um espaço na entrada


3

Pitão, 5 bytes

.gksc

Experimente aqui!

Recebe a entrada como uma string Python (ou seja, envolvida em aspas, aspas e barras escapadas, conforme necessário).

Explicação:

    c    Split (implied) input on whitespace
   s     Sum together
.gk      Group by value

Se você garantir pelo menos um espaço na entrada, há uma solução de 4 bytes:

t.gk

Experimente aqui!

Explicação:

 .gk (Q)  groups the characters in the string by their value
           this sorts them by their value, which guarantees that spaces are first
t         Remove the first element (the spaces)

3

PowerShell v2 +, 44 bytes

[char[]]$args[0]-ne32|group|%{-join$_.Group}

Recebe a entrada $args[0]como uma sequência literal de argumento da linha de comando. Lança isso como uma charmatriz e usa o operador -not equal para extrair espaços (ASCII32 ). Isso funciona porque a conversão tem uma precedência de ordem mais alta e, quando uma matriz é usada como operador à esquerda com um escalar à direita, ela age como um filtro.

Passamos esse conjunto de caracteres para Group-Object, que faz exatamente o que diz. Observe que, como estamos passando caracteres , não cadeias, isso agrupa adequadamente com distinção entre maiúsculas e minúsculas.

Agora, temos um (s) objeto (s) personalizado (s) com nomes de grupos, contagens etc. Se apenas imprimirmos, teremos uma série de resultados estranhos. Então, precisamos tubulação aqueles em um loop |%{...}e cada iteração -joino .Groupconjunto em uma única seqüência. Essas seqüências resultantes são deixadas no pipeline e a saída é implícita na conclusão do programa.

Exemplo

PS C:\Tools\Scripts\golfing> .\exploded-view-of-substrings.ps1 'Programming Puzzles and Code Golf'
PP
rr
ooo
gg
aa
mm
i
nn
u
zz
ll
ee
s
dd
C
G
f

3

Dyalog APL , 11 bytes

Função retornando lista de strings.

(⊂∩¨∪)~∘' '

(⊂∩¨∪) a interseção da totalidade e seus caracteres únicos

~∘' ' exceto espaços

TryAPL online!


2

Processando, 109 bytes

void s(char[] x){x=sort(x);char l=0;for(char c:x){if(c!=l)println();if(c!=' '&&c!='\n'&&c!='\t')print(c);l=c;}}

É a abordagem da força bruta, classifica a matriz e passa por ela. Se não corresponder ao último caractere impresso, imprima uma nova linha primeiro. Se estiver em branco, pule a etapa de impressão.


2

Javascript (usando a Biblioteca externa - Enumerável) ( 78 67 bytes)

 n=>_.From(n).Where(y=>y!=' ').GroupBy(x=>x).WriteLine(y=>y.Write())

Link para lib: https://github.com/mvegh1/Enumerable

Explicação do código: Isto é o que Enumerable foi feito para fazer! Carregue a sequência na biblioteca, que a converte em uma matriz de caracteres. Filtre as entradas de espaço em branco. Agrupar por char. Escreva cada grupo em uma linha, de acordo com o predicado especificado. Esse predicado diz para unir todos os elementos do grupo atual em uma sequência, sem um delimitador.

insira a descrição da imagem aqui



2

Perl6, 48 47 45

slurp.comb.Bag.kv.map:{$^a.trim&&say $a x$^b}

Obrigado ao manatwork pelas melhorias.


1
Não é uma grande melhoria, mas $a.trimparece fazê-lo para a condição.
manatwork

Parece que os operadores lógicos ainda não precisam de espaços ao seu redor, então $^a.trim&&say $a x$^bfunciona. (Desculpe para adicionar o dicas byte por byte, mas esta é a minha primeira tentativa em Perl6.)
manatwork

Erro de digitação, você acidentalmente removeu a abertura {.
precisa saber é

1

Ruby, 46 bytes

Experimente online!

->s{(s.chars-[' ']).uniq.map{|c|c*s.count(c)}}

Minha versão original do programa, 48 bytes após adicionar o nsinalizador:

p gsub(/\s/){}.chars.uniq.map{|c|c*$_.count(c)}

Você pode substituir .count(c)com .count c?
Cyoce 26/08/16

@ Não, porque o *operador está presente nas proximidades, para que o analisador se queixe.
Value Ink

s.chars- [''] | [] dentro dos parênteses evitaria o uniq
PT

@GB Seria, mas se o encadearmos, mapele precisa de parênteses extras e ((s.chars-[' '])|[]).maptem o mesmo número de caracteres que(s.chars-[' ']).uniq.map . E a outra maneira, mais curto para verificar personagens únicos (via regex) já está coberto por @Jordan em outra resposta
Valor Ink

Funciona dentro dos colchetes, você não precisa de colchetes extras porque a precedência de '-' é maior.
GB

1

Python, 107

Pode ser encurtado por lambda, mas mais tarde

x=sorted(input())
i=0
while i<len(x):x[i:]=['  '*(x[i]!=x[i-1])]+x[i:];i-=~(x[i]!=x[i-1])
print("".join(x))

1

CJam, 10 bytes

{S-$e`::*}

Um bloco sem nome que espera a cadeia no topo da pilha e a substitui por uma lista de cadeias.

Experimente online!

Explicação

S-  Remove spaces.
$   Sort.
e`  Run-length encode, gives pairs [R C], where R is the run-length and
    C is the character.
::* Repeat the C in each pair R times.

1

Lisp comum, 123

(lambda(s &aux(w(string-trim" "(sort s'char<))))(princ(elt w 0))(reduce(lambda(x y)(unless(char= x y)(terpri))(princ y))w))

Ungolfed:

(lambda (s &aux (w (string-trim " " (sort s 'char<))))
  (princ (elt w 0))
  (reduce
    (lambda (x y) 
      (unless (char= x y) (terpri))
      (princ y))
  w))

Não é a linguagem mais amigável para o golfe. Provavelmente, isso pode ser modificado para retornar a lista de listas em vez de imprimir a string.


1

Emacs, 36 pressionamentos de tecla

C-SPACE C-EM-xsort-rTABRETURN.RETURN.RETURNC-AC-M-S-%\(\(.\)\2*\)RETURN\1C-QC-JRETURN!

Resultado

A man, a plan, a canal: Panama! ->

!
,,
:
A
P
aaaaaaaaa
c
ll
mm
nnnn
p

Explicação

  1. C-SPACE C-E
  2. M-x sort-rTAB RETURN .RETURN .RETURN
  3. C-A
  4. C-M-S-% \(\(.\)\2*\)RETURN\1 C-Q C-JRETURN !

  1. Selecione a linha de entrada;
  2. Ligue sort-regexp-fieldscom argumentos .e. ;
    • Argumento 1: Regexp especificando registros para classificar
    • Argumento # 2: Regexp chave de especificação dentro de registros
  3. Retorno no início da linha;
  4. Aplique a substituição regexp \(\(.\)\2*\)-> \1\nem todas as correspondências.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.