Detriplicar uma sequência


39

Muitos idiomas têm maneiras integradas de se livrar de duplicatas ou "desduplicar" ou "unificar" uma lista ou string. Uma tarefa menos comum é "descriptografar" uma string. Ou seja, para cada personagem que aparece, os dois primeiros ocorrências são mantidas.

Aqui está um exemplo em que os caracteres que devem ser excluídos são rotulados com ^:

aaabcbccdbabdcd
  ^    ^ ^^^ ^^
aabcbcdd

Sua tarefa é implementar exatamente esta operação.

Regras

A entrada é uma única sequência, possivelmente vazia. Você pode assumir que ele contém apenas letras minúsculas no intervalo ASCII.

A saída deve ser uma única sequência com todos os caracteres removidos que já apareceram pelo menos duas vezes na sequência (para que as duas ocorrências mais à esquerda sejam mantidas).

Em vez de strings, você pode trabalhar com listas de caracteres (ou strings singleton), mas o formato deve ser consistente entre entrada e saída.

Você pode escrever um programa ou uma função e usar qualquer um dos nossos métodos padrão de recebimento de entrada e saída.

Você pode usar qualquer linguagem de programação , mas observe que essas brechas são proibidas por padrão.

Isso é , então a resposta mais curta e válida - medida em bytes - vence.

Casos de teste

Cada par de linhas é um caso de teste, entrada seguida por saída.



xxxxx
xx
abcabc
abcabc
abcdabcaba
abcdabc
abacbadcba
abacbdc
aaabcbccdbabdcd
aabcbcdd

Entre os melhores

O snippet de pilha na parte inferior desta postagem gera um cabeçalho das respostas a) como uma lista da solução mais curta por idioma eb) como um cabeçalho geral.

Para garantir que sua resposta seja exibida, inicie-a com um título, usando o seguinte modelo de remarcação:

## Language Name, N bytes

onde Nestá o tamanho do seu envio. Se você melhorar sua pontuação, poderá manter as pontuações antigas no título, identificando-as. Por exemplo:

## Ruby, <s>104</s> <s>101</s> 96 bytes

Se você quiser incluir vários números em seu cabeçalho (por exemplo, porque sua pontuação é a soma de dois arquivos ou deseja listar as penalidades de sinalizador de intérprete separadamente), verifique se a pontuação real é o último número no cabeçalho:

## Perl, 43 + 3 (-p flag) = 45 bytes

Você também pode transformar o nome do idioma em um link que será exibido no snippet:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes


5
Cordas Singleton ... stringletons?
dkudriavtsev 28/07

Respostas:



15

JavaScript (ES6), 42 48

Editar Um enorme 6 bytes salvos thx @Neil

s=>s.replace(k=/./g,c=>(k[c]+=c)[11]?'':c)

Explicação: Uso as propriedades 'a' ... 'z' do objeto kpara armazenar informações para cada caractere (o objeto k é uma expressão regular, neste caso, apenas para salvar bytes). Essas propriedades são inicialmente undefined. No javascript, adicionar um número a undefinedNaN(bastante sensato), mas adicionar uma string 'X' dá "undefinedX"- uma string de comprimento 10 (bobo). Adicionando mais caracteres, você obtém seqüências mais longas. Se a sequência obtida para um determinado caractere for maior que 11, esse caractere não será copiado para a saída.

Teste

F=
s=>s.replace(k=/./g,c=>(k[c]+=c)[11]?'':c)

test=`

xxxxx
xx
abcabc
abcabc
abcdabcaba
abcdabc
abacbadcba
abacbdc
aaabcbccdbabdcd
aabcbcdd`.split`\n`
for(i=0;i<test.length;)
  a=test[i++],b=test[i++],r=F(a),
  console.log(r==b?'OK':'KO',a,'->',r,b)


A rigor, uma linha vazia é um dos casos de teste.
314 Neil

@Neil ok acrescentou o teste string vazia
edc65

Se você alternar para entrada e saída da matriz, poderá usar .filter para salvar mais 12 caracteres. v=>v.filter(x=>!(v[x]+=x)[11]). Parabéns pelo hack "indefinido".
Grax32 31/01

@ Thanx Grax, mas muito diferente. Deverá publicá-lo você mesmo
edc65 31/01

14

Python 2, 48 bytes

lambda s:reduce(lambda r,c:r+c*(r.count(c)<2),s)

c[r.count(c)/2:]é uma alternativa do mesmo comprimento para c*(r.count(c)<2).


49 bytes:

r=''
for c in input():r+=c*(r.count(c)<2)
print r

12

Retina , 17 bytes

(.)(?<=\1.*\1.+)

Experimente online!

Substituição simples de regex - combine um caractere se ele já apareceu duas vezes e remova-o.


Eu também tentei um loop e um grupo repetido com{2} , ambos com 18 bytes.
Kobi

1
Eu tenho 14 usando um recurso adicionado recentemente. ;)
Martin Ender

Eu sabia que havia algo. Eu olhei para limites, provavelmente não esse. Vou verificar novamente.
Kobi

3
Ah, acho que encontrei a resposta de Martin. Eu tive alguns problemas quando estava tentando antes, acho que porque não considerava como a desduplicação funcionaria em uma entrada de várias linhas. O spoiler (com 5 bytes adicionado para activar o modo de por-linha): retina.tryitonline.net/...
FryAmTheEggman

@FryAmTheEggman - Bom, não encontrei este. Sinta-se à vontade para adicionar uma resposta - acho que isso é muito diferente da minha resposta e não me senti à vontade editando-a :P. Obrigado!
Kobi

6

Braquilog , 25 bytes

.v|s.g:.z:1a
:2fl<3
he~t?

Experimente online! ou verifique todos os casos de teste .

Explicação

Isso funciona porque s - Subsetserá unificado primeiro com subconjuntos maiores, por exemplo, porque "aaa"ele tentará "aa"antes "a".

  • Predicado principal:

      .v         input = Output = ""
    |          Or
      s.         Output is an ordered subset of the input
      g:.z       Zip each character of the output with the output itself
      :1a        Apply predicate 1 on each element of the zip
    
  • Predicado 1: verifique se todos os caracteres aparecem apenas no máximo duas vezes. Input =[String:Char]

    :2f        Find all valid outputs of predicate 2 (i.e. one output per occurence
                   of the char)
    l<3        There are less than 3 occurences
    
  • Predicado 2: Consiga a ocorrência de um personagem. Input =[String:Char]

    he         Take a character of the string in the input
      ~t?      That character is the char of the input
    

6

> <> , 22 bytes

i:0(?;::9g:}2(?o{1+$9p

Experimente online! Usa o codebox para acompanhar as contagens até o momento.

i                       Read a char c of input
 :0(?;                  Halt if EOF
      :                 Make a copy - stack has [c c] at the top
       :9g              Get count stored at (c, 9)
          :}            Copy the count and move to bottom of stack
            2(?o        If the count is less than 2, output c
                {1+     Move the count back to the top of the stack and increment
                   $9p  Update cell at (c, 9)
                        [Instruction pointer moves to start as ><> is toroidal]

6

J, 20 15 bytes

#~(3>[+/@:={:)\

Isso define uma função monádica que pega e retorna uma string. Experimente aqui . Uso:

   f =: #~(3>[+/@:={:)\
   f 'abaacbb'
abacb

Explicação

Eu mudei para o mesmo algoritmo usado por algumas outras soluções, pois acabou sendo mais curto ...

#~(3>[+/@:={:)\  Input is y.
  (          )\  For each prefix of y:
          =        compute the equality vector
     [     {:      of the prefix and its last element, and
      +/@:         take its sum. Now we have a vector r such that y[i] has its
                   r[i]'th occurrence at position i.
   3>              Mark those coordinates where r[i] < 3.
#~               Remove the non-marked characters from y.

6

Haskell, 40 39 bytes

foldl(\s c->s++[c|filter(==c)s<=[c]])""

Exemplo de uso: foldl(\s c->s++[c|filter(==c)s<=[c]])"" "aaabcbccdbabdcd"-> "aabcbcdd".

Mantenha o próximo caractere c se a sequência de todos os cs até agora for lexicográfica menor ou igual à sequência singleton [c].

Edit: @xnor salvou um byte alternando da compreensão da lista para filter. Obrigado!


Sua alternativa poderia ser usada filter(==c)s<=[c]para salvar um byte.
Xnor

5

Perl, 22 bytes

Código de 21 bytes + 1 para -p.

s/./$&x(2>${$&}++)/ge

Uso

perl -pe 's/./$&x(2>${$&}++)/ge' <<< 'aaabcbccdbabdcd'
aabcbcdd

5

C, 57 bytes

Ligue f()com a cadeia para detriplicar. A função modifica seu parâmetro. Requer C99 devido à fordeclaração -loop.

f(char*p){for(char*s=p,m[256]={0};*s=*p;s+=++m[*p++]<3);}

Você não pode colocar a declaração de sna primeira declaração do for?
Martin Ender

Em C99 você pode. Só não o fiz porque gosto de manter os C89 compatíveis.
27416 owacoder

5

JavaScript (ES6), 35 bytes

s=>s.filter(c=>(s[c]=(s[c]|0)+1)<3)

Pega uma matriz de caracteres como entrada e retorna a matriz com descrições duplicadas.


Agradável. Você poderia fazer c=>(s[c]=-~s[c])<3para salvar alguns bytes.
ETHproductions

Eu tinha perdido que você poderia usar matrizes como entrada e tinha escrito uma função usando map. Golfe, parecia essencialmente com o seu. a principal diferença era a atribuição, que, se você alternar, economizará alguns bytes. Tente s.filter(c=>(s[c]=s[c]+1|0)<3)por 33 bytes. EDIT: Opa, perdeu o comentário acima de mim, que é ainda melhor :)
Jan

4

PowerShell v2 +, 31 bytes

$args-replace'(.)(?<=\1.*\1.+)'

Usa o mesmo regex que na resposta Retina de Kobi , encapsulado no -replaceoperador PowerShell . Funciona porque ambos estão usando regex com sabor .NET em segundo plano.

Como alternativa, sem regex, 56 bytes

$b=,0*200;-join([char[]]$args[0]|%{"$_"*($b[$_]++-lt2)})

Cria uma matriz auxiliar $bpreviamente preenchida com 0s. Lança a sequência de entrada $args[0]como uma charmatriz, passa por um loop |%{...}. Cada iteração gera o caractere atual $_como uma sequência "$_"multiplicada por um booleano que é apenas $TRUE(convertido implicitamente para 1aqui) se o ponto apropriado na matriz auxiliar for menor que 2(ou seja, já não vimos esse caracter duas vezes). A coleção resultante de seqüências de caracteres é encapsulada em parênteses e -joineditada em conjunto para formar uma única sequência de saída. Isso é deixado no pipeline e a produção está implícita.


regex é imbatível. :) eu beleave uma tabela de dispersão é melhor, em seguida, uma matriz para a variante sem regex: $b=@{};-join($args|% t*y|?{++$b.$_-lt3}).
Mazzy

1
@mazzy Para a variante sem regex e seu código, ela precisaria ser uma versão mais nova que o PowerShell 2. Como resultado, acho que manterei essa resposta sem alterações. Você pode postar seu código como uma resposta separada!
AdmBorkBork 10/09

a hashtable apareceu na versão 3.0? Está bem. Obrigado.
Mazzy

4

Mathematica, 39 bytes

Fold[If[Count@##<2,Append@##,#]&,{},#]&

Função anônima. Pega uma lista de caracteres como entrada e retorna a lista descriptografada como saída. Usa o método de dobrar a lista e rejeitar elementos em triplicado, não é muito complicado.


4

05AB1E, 12 bytes

vyˆ¯y¢O3‹iy?

Explicação

v            # for each char in input
 yˆ          # push to global array
   ¯y¢O3‹i   # if nr of occurrences are less than 3
          y? # print it

Experimente online


4

MATL , 8 bytes

t&=Rs3<)

Experimente online!

Explicação

t      % Input string implicitly. Push another copy
&=     % Matrix of all pairwise equality comparisons of string elements
R      % Keep only upper triangular part, making the rest of the entries zero
s      % Sum of each column. This gives a vector with number of occurrences
       % of the current character up to the current position
3<     % True for entries that are less than 3
)      % Use as logical index into initial copy of the input. Display implicitly

Exemplo

Supondo entrada 'aaababbc', a pilha contém o seguinte após as instruções indicadas:

  • t

    'aaababbc'
    'aaababbc'
    
  • t&=

    'aaababbc'
    [ 1 1 1 0 1 0 0 0;
      1 1 1 0 1 0 0 0;
      1 1 1 0 1 0 0 0;
      0 0 0 1 0 1 1 0;
      1 1 1 0 1 0 0 0;
      0 0 0 1 0 1 1 0;
      0 0 0 1 0 1 1 0;
      0 0 0 0 0 0 0 1 ]
    
  • t&=R

    'aaababbc'
    [ 1 1 1 0 1 0 0 0;
      0 1 1 0 1 0 0 0;
      0 0 1 0 1 0 0 0;
      0 0 0 1 0 1 1 0;
      0 0 0 0 1 0 0 0;
      0 0 0 0 0 1 1 0;
      0 0 0 0 0 0 1 0;
      0 0 0 0 0 0 0 1 ]
    
  • t&=Rs

    'aaababbc'
    [ 1 2 3 1 4 2 3 1 ]
    
  • t&=Rs3<

    'aaababbc'
    [ true true false true false true false true ]
    
  • t&=Rs3<)

    'aabbc'
    

4

Retina , 14 bytes

D`(.)(?<=\1.*)

Verifique todos os casos de teste. ( %Ativa o modo por linha)

Usa o novo estágio "Deduplicate" para salvar alguns bytes sobre a abordagem de Kobi . A eliminação de duplicatas reúne uma lista de todas as correspondências no regex e substitui todas, exceto a primeira, pela sequência vazia. A regex corresponde a um caractere que já aparece uma vez na cadeia, o que significa que os dois primeiros serão mantidos.



3

K, 18 bytes

  g:{x{?x@<x}@,/2#'=x}
  g "abc"
"abc"
  g "aaabcbccdbabdcd"
"aabcbcdd"

  /k4 request test vectors from internet
  R:"GET /raw/ftHe0bpE HTTP/1.0\r\nHost: pastebin.com\r\n\r\n"
  t:+0N 2#t@1_&|\(0=#:)'t:1_"\r\n"\:`:http://pastebin.com:80 R 

  /k4 no internet? use a file called "t.txt" in current directory
  t:+0N 2#0:`:t.txt

  /k6?
  t:+0N 2#0:"t.txt"

  /visually inspect test cases
  g't[0]
(();"xx";"abcabc";"abcdabc";"abacbdc";"aabcbcdd")

  /do all tests pass?
  |/ t[1] {$[0=#x;0=#y;x~y]}' g't[0]
1b

O K4 está disponível para download gratuito ; K6 está em desenvolvimento . Se você baixou o KDB, pode entrar no K com barra invertida .

Pode ser mais fácil ver isso desmembrado, mas primeiro alguma sintaxe: g:xdefine gcomo x. {x+1}é uma função que recebe um argumento x . Em K, o primeiro argumento para uma função é x(o segundo é ye o terceiro é z. Não precisa de um quarto).

Agora:

x:"aaabcbccdbabdcd"

=xsignifica grupo x , que produz:

"abcd"!(0 1 2 10;3 5 9 11;4 6 7 13;8 12 14)

2#'significa dois retirados (de) cada um que produz

"abcd"!(0 1;3 5;4 6;8 12)

Como você pode ver, esses são os desvios das duas primeiras partidas de cada personagem. Os 2 podem ser generalizados.

,/significa juntar-se a cada um e é chamado de raze . Isso nos dará apenas os valores do nosso dicionário. Assim, ,/"abcd"!(0 1;3 5;4 6;8 12)produz:

0 1 3 5 4 6 8 12

que precisamos classificar. {x@<x}@é um idioma que os programadores costumam ver (Q chama de asc ), que diz x na classificação x . Desmembrando:

  <0 1 3 5 4 6 8 12
0 1 2 4 3 5 6 7

retornou os índices da matriz classificada, que queremos obter da matriz original. x@ysignifica x em y, portanto, indexa a matriz com os índices da classificação (se isso faz algum sentido).

  {x@<x}@0 1 3 5 4 6 8 12
0 1 3 4 5 6 8 12

que simplesmente indexamos agora em nossa matriz original. Nós poderia dizer x@aqui, mas K suporta um conceito muito poderoso que pode tirar vantagem de aqui: aplicação de função é a indexação. Isso significa que a[0]pode estar procurando o slot zeroth aou pode estar aplicando o 0à função chamada a. A razão pela qual precisávamos @anteriormente {x@<x}é porque x<ysignifica xs menor que ys : os operadores em K têm uma forma diádica (dois argumentos) e uma forma monádica (um argumento) que vem da APL. Q não tem essa "ambivalência".


Bem-vindo ao PPCG! Ótima primeira resposta. :)
Martin Ender

Eu tenho algumas perguntas. 1. O K4 é o mesmo idioma para o qual você vincula (Q / kdb +)? 2. Você poderia mostrar como chamar sua função em uma entrada ou como os itens em testVectors.txt devem ser formatados?
Dennis

@Dennis 1. Sim. Pressione barra invertida para ir de Q a K. 2. Assim como elas aparecem na pergunta: pastebin.com/ftHe0bpE exemplo de chamada:g"aaabcbccdbabdcd"
geocar

OK obrigado. Não foi possível obter a parte do arquivo funcionando, mas g"..."faz o truque. Infelizmente, seu código retorna aabbccpara entrada abc.
Dennis

@ Dennis Você pode ter feito algo errado: {x{?x@<x}@,/2#'=x}"abc"definitivamente retorna "abc". Voltaria "aabbcc"se você perdesse o ?distinto.
Geocar #

2

Python 2, 51 bytes

f=lambda s:s and f(s[:-1])+s[-1]*(s.count(s[-1])<3)

Teste em Ideone .


2

Java 8 lambda, 90 caracteres

i->{int[]o=new int[128];String r="";for(char c:i.toCharArray())if(++o[c]<3)r+=c;return r;}

Versão não destruída:

public class Q86503 {

    static String detriplicate(String input) {
        int[] occurences = new int[128];
        String result = "";
        for (char c : input.toCharArray()) {
            if (++occurences[c] < 3) {
                result += c;
            }
        }
        return result;
    }
}

Cria uma matriz para todos os caracteres ascii. Se um caractere ocorrer, o contador correspondente será aumentado. Se for maior que 2, o caractere não será anexado à sequência de resultados. Muito fácil, muito curto;)


2

Perl 6, 27 bytes

{.comb.grep({++%.{$_} <3})}

Explicação:

{.comb.grep({++%.{$_} <3})}
{                         } # a function
 .comb                      # get all the characters in the argument
      .grep({           })  # filter
               %.           # an anonymous hash (shared between calls to grep)
             ++  {$_}       # increment the value at the current key (current letter).
                            # if the key doesn't exist, it defaults to 0 (then gets incremented)
                      <3    # return True if it wasn't seen 3 times

(Nota: o Perl 6 não é tão "orientado para o golfe" quanto sua irmã Perl 5 ... Então sim, esse espaço antes do <necessário é necessário. O %.{}hash é anônimo).



2

SmileBASIC, 77 72 69 68 bytes

DIM R[#Y]READ S$WHILE""<S$Q=ASC(S$)INC R[Q]?SHIFT(S$)*(R[Q]<3);
WEND

Explicado:

DIM R[128] 'array to store letter frequencies
READ S$ 'get input string
WHILE""<S$ 'much shorter than LEN(S$)
 Q=ASC(S$) 'get ascii value of first character in S$
 INC R[Q]
 ?SHIFT(S$)*(R[Q]<3); 'remove the first character of S$, and print it if there are less than 3 occurrences.
WEND

Bem-vindo ao ppcg! Bom primeiro post!
Rɪᴋᴇʀ

1

Lisp comum, 127

(lambda(s)(map()(lambda(x)(flet((p(b)(1+(position x s :start b))))(setf s(remove x s :start(p(p 0))))))(remove-duplicates s))s)

Pretty-impresso

(lambda (s)
  (map nil
       (lambda (x)
         (flet ((p (b)
                  (1+ (position x s :start b))))
           (setf s (remove x s :start (p (p 0))))))
       (remove-duplicates s))
  s)

1

Q , 52 bytes

q)f2:{x asc raze{distinct 2#where x}each x~'/:distinct x}
q)f2 each testList
"xx"
"abcabc"
"abcdabc"
"abacbdc"
"aabcbcdd"
q)

1

K , 27 bytes

    f:{x{x@<x}@,/{?2#&x}'x~'/:?x}
    testList:("xxxxx";"abcabc";"abcdabcaba";"abacbadcba";"aaabcbccdbabdcd")
    f'testList
("xx";"abcabc";"abcdabc";"abacbdc";"aabcbcdd")

1

Ruby , 79 62 57 bytes

Isso é bastante pesado, mas não tenho certeza se posso jogar muito melhor no momento. Todas as sugestões de golfe são bem-vindas. Experimente online!

Edit: -17 bytes graças ao Value Ink, sugerindo uma maneira mais eficiente de remover caracteres em triplicado. -5 bytes da remoção do .uniqmétodo.

->s{s.chars.map{|a|s[s.rindex a]=""while s.count(a)>2};s}

Ungolfed:

def g(s)
 s.chars.each do |a|
  while s.count(a) > 2
   i = s.rindex(a)
   s[i] = ""
  end
 end
 return s
end

62 bytes:->s{s.chars.uniq.map{|a|s[s.rindex a]=""while s.count(a)>2};s}
Value Ink

1

JavaScript, 30 bytes

v=>v.filter(x=>!(v[x]+=x)[11])

Usando o método que o @ edc65 surgiu para contar, mas com um filtro de matriz. Quando o caractere aparece pela primeira vez, o valor do objeto fica "indefinido" mais o caractere (ou seja, "indefinidox"). A próxima vez que o valor do objeto se tornar "undefinedxx".

Depois disso, v [x] [11] retorna true e quando combinado com o operador not, false, significando caracteres que já apareceram duas vezes serão filtrados.


0

Javascript (usando biblioteca externa) (80 bytes)

Essa foi boa! Não ganhou, mas foi divertido

n=>{a={};return _.From(n).Where(x=>{b=a[x]?a[x]++:a[x]=1;return b<2}).Write("")}

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

Explicação do código: O método aceita uma string, a biblioteca a analisa como uma matriz de caracteres e a cláusula Where é um predicado de filtragem complexo que verifica o hashmap 'a' quanto à presença do caractere atual. Se existir, incremente o contador; caso contrário, defina como 1. Se <2, o predicado (e o caractere atual) for aprovado, o restante falhará.

insira a descrição da imagem aqui


Você pode evitar o uso de um return, mas fazer a sua função de uma lista separada por vírgulas de um expressões entre parênteses: n=>(a={},_From(n)....). A última expressão é o valor de retorno. Em sua Wherefunção, você pode eliminar o intermediário binteiramente comparando contra o resultado da cessão ou incremento: x=>(a[x]?a[x]++:a[x]=1)<2.
Apsillers

Finalmente, você pode evitar o uso de uma biblioteca externa em tudo (e salvar bytes) usando o reticências corda-split e filtercom join: [...n].filter(...).join(""). Inverta a lógica verdadeira / falsa ao mudar Wherepara filter.
apsillers

Ahh boas observações! Ill dar uma olhada mais tarde a sua sugestão
applejacks01

0

Clojure, 72 bytes

#(apply str(reduce(fn[r c](if(<(count(filter #{c}r))2)(conj r c)r))[]%))

Tantos bytes ...


0

Pascal (FPC) , 103 bytes

var a:array['a'..'z']of word;c:char;begin repeat read(c);inc(a[c]);if a[c]<3then write(c)until eof end.

Experimente online!

Explicação:

var a:array['a'..'z']of word; //used for counting occurences of characters in the input
                              //array indices are accessed by chars
    c:char;
begin
  repeat
    read(c);                  //read a character from input
    inc(a[c]);                //increment the count of that character (its number in array)
    if a[c]<3 then write(c)   //if this is character's 1st or 2nd occurence, output it
  until eof                   //go back to reading if input is not read completely
end.
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.