Detriplicar una cadena


39

Muchos idiomas tienen formas integradas para deshacerse de los duplicados, o "deduplicar" o "uniquificar" una lista o cadena. Una tarea menos común es "detriplicar" una cadena. Es decir, por cada personaje que aparece, el primero se mantienen las dos ocurrencias.

Aquí hay un ejemplo donde los caracteres que deben eliminarse están etiquetados con ^:

aaabcbccdbabdcd
  ^    ^ ^^^ ^^
aabcbcdd

Su tarea es implementar exactamente esta operación.

Reglas

La entrada es una sola cadena, posiblemente vacía. Puede suponer que solo contiene letras minúsculas en el rango ASCII.

La salida debe ser una sola cadena con todos los caracteres eliminados que ya han aparecido al menos dos veces en la cadena (por lo que se conservan las dos ocurrencias más a la izquierda).

En lugar de cadenas, puede trabajar con listas de caracteres (o cadenas de un solo tono), pero el formato debe ser coherente entre la entrada y la salida.

Puede escribir un programa o una función y utilizar cualquiera de nuestros métodos estándar para recibir entradas y proporcionar salidas.

Puede usar cualquier lenguaje de programación , pero tenga en cuenta que estas lagunas están prohibidas de forma predeterminada.

Este es el , por lo que gana la respuesta válida más corta, medida en bytes .

Casos de prueba

Cada par de líneas es un caso de prueba, entrada seguido de salida.



xxxxx
xx
abcabc
abcabc
abcdabcaba
abcdabc
abacbadcba
abacbdc
aaabcbccdbabdcd
aabcbcdd

Tabla de clasificación

El Fragmento de pila al final de esta publicación genera una tabla de clasificación a partir de las respuestas a) como una lista de la solución más corta por idioma yb) como una tabla de clasificación general.

Para asegurarse de que su respuesta se muestre, comience con un título, usando la siguiente plantilla de Markdown:

## Language Name, N bytes

¿Dónde Nestá el tamaño de su envío? Si mejora su puntaje, puede mantener los puntajes antiguos en el título, tachándolos. Por ejemplo:

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

Si desea incluir varios números en su encabezado (por ejemplo, porque su puntaje es la suma de dos archivos o desea enumerar las penalizaciones de la bandera del intérprete por separado), asegúrese de que el puntaje real sea el último número en el encabezado:

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

También puede hacer que el nombre del idioma sea un enlace que luego aparecerá en el fragmento:

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


55
Cuerdas Singleton ... ¿Stringletons?
dkudriavtsev

Respuestas:



15

JavaScript (ES6), 42 48

Editar la friolera de 6 bytes guardados gracias a @Neil

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

Explicación: Utilizo las propiedades 'a' ... 'z' del objeto kpara almacenar información para cada carácter (el objeto k es una expresión regular en este caso solo para guardar bytes). Estas propiedades son inicialmente undefined. En javascript, agregar un número para undefineddar NaN(bastante razonable), pero agregar una cadena 'X' da "undefinedX"- una cadena de longitud 10 (tonto). Agregando más caracteres obtienes cadenas más largas. Si la cadena obtenida para un carácter dado es mayor que 11, ese carácter no se copia a la salida.

Prueba

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)


Estrictamente hablando, una línea vacía es uno de los casos de prueba.
Neil

@Neil ok agregó la prueba de cadena vacía
edc65

Si cambia a entrada y salida de matriz, puede usar .filter para guardar 12 caracteres más. v=>v.filter(x=>!(v[x]+=x)[11]). Felicitaciones por el truco "indefinido".
Grax32

@Grax gracias pero muy diferente. Debería publicarlo usted mismo
edc65

14

Python 2, 48 bytes

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

c[r.count(c)/2:]es una alternativa de la misma longitud a 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.+)

Pruébalo en línea!

Reemplazo simple de expresiones regulares: empareja un personaje si ya apareció dos veces y retíralo.


También probé un bucle y un grupo repetido con{2} ambos con 18 bytes.
Kobi

1
Tengo 14 usando una función agregada recientemente. ;)
Martin Ender

Sabía que había algo. Miré los límites, probablemente no ese. Lo revisaré de nuevo.
Kobi

3
Ah, creo que encontré la respuesta de Martin. Tuve algunos problemas cuando lo intentaba antes, creo que porque no consideré cómo funcionaría la deduplicación en una entrada de varias líneas. Spoiler (con 5 bytes agregados para habilitar el modo por línea): retina.tryitonline.net/…
FryAmTheEggman

@FryAmTheEggman - Bien, no encontré este. Siéntase libre de agregar una respuesta: creo que esto es muy diferente de mi respuesta y no me sentí cómodo editándola :P. ¡Gracias!
Kobi

6

Brachylog , 25 bytes

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

Pruébalo en línea! o verificar todos los casos de prueba .

Explicación

Esto funciona porque s - Subsetprimero se unificará con subconjuntos más grandes, por lo tanto, por ejemplo "aaa", lo intentará "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: compruebe que todos los caracteres solo aparezcan dos veces como máximo. Entrada =[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: Obtener una ocurrencia de un personaje. Entrada =[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

Pruébalo en línea! Utiliza el cuadro de código para realizar un seguimiento de los recuentos hasta ahora.

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>[+/@:={:)\

Esto define una función monádica que toma y devuelve una cadena. Pruébalo aquí . Uso:

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

Explicación

Cambié al mismo algoritmo que usan otras soluciones, ya que resultó ser más corto ...

#~(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]])""

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

Mantenga el siguiente carácter csi la cadena de todos los cs hasta ahora son lexicográficos menores o iguales que la cadena singleton[c] .

Editar: @xnor guardó un byte al cambiar de comprensión de lista a filter. ¡Gracias!


Su alternativa podría hacer filter(==c)s<=[c]para guardar un 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

Llame f()con la cuerda para detriplicar. La función modifica su parámetro. Requiere C99 debido a la fordeclaración -loop.

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

¿No puedes poner la declaración sen la primera declaración de la for?
Martin Ender

En C99 puedes. Simplemente no lo hice porque me gusta mantener los campos de golf C89 compatibles.
owacoder

5

JavaScript (ES6), 35 bytes

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

Toma una matriz de caracteres como entrada y devuelve la matriz destriplicada.


Agradable. Podría hacer c=>(s[c]=-~s[c])<3para guardar algunos bytes.
ETHproductions

Extrañaba que pudieras usar matrices como entrada y había escrito una función usando map. Golfizado se parecía esencialmente al tuyo. La principal diferencia era la asignación, que si la cambia, ahorrará unos pocos bytes. Prueba s.filter(c=>(s[c]=s[c]+1|0)<3)por 33 bytes. EDITAR: Whoops, se perdió el comentario sobre mí, eso es aún mejor :)
Jan

4

PowerShell v2 +, 31 bytes

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

Utiliza la misma expresión regular que en la respuesta Retina de Kobi , simplemente encapsulada en el -replaceoperador PowerShell . Funciona porque ambos usan .NET-taste regex en segundo plano.

Alternativamente, sin expresiones regulares, 56 bytes

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

Crea una matriz auxiliar $bpreviamente rellenada con 0s. Lanza la cadena de entrada $args[0]como una charmatriz, la canaliza a través de un bucle|%{...} . Cada iteración genera el carácter actual $_como una cadena "$_"multiplicada por un booleano que solo $TRUE(se arroja implícitamente 1aquí) si el punto apropiado en la matriz auxiliar es menor que 2(es decir, no hemos visto este carácter dos veces). La colección resultante de cadenas se encapsula en parens y se editan -joinjuntas para formar una sola cadena de salida. Eso queda en la tubería y la salida es implícita.


regex es inmejorable. :) I beleave una tabla hash es mejor que una matriz para la variante sin expresión regular: $b=@{};-join($args|% t*y|?{++$b.$_-lt3}).
mazzy

1
@mazzy Para la variante sin expresiones regulares y su código, debería ser una versión más nueva que PowerShell 2. Como resultado, creo que mantendré esta respuesta sin cambios. ¡Sin embargo, puede publicar su código como una respuesta separada!
AdmBorkBork

¿apareció la tabla hash en la versión 3.0? Okay. Gracias.
mazzy

4

Mathematica, 39 bytes

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

Función anónima. Toma una lista de caracteres como entrada y devuelve la lista destriplicada como salida. Utiliza el método de plegar sobre la lista y rechazar elementos triplicados, no es demasiado complicado.


4

05AB1E, 12 bytes

vyˆ¯y¢O3‹iy?

Explicación

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

Pruébalo en línea


4

MATL , 8 bytes

t&=Rs3<)

Pruébalo en línea!

Explicación

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

Ejemplo

Suponiendo una entrada 'aaababbc', la pila contiene lo siguiente después de las declaraciones 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 los casos de prueba. ( %Activa el modo por línea)

Utiliza la nueva etapa "Deduplicar" para guardar un par de bytes sobre el enfoque de Kobi . Deduplicate reúne una lista de todas las coincidencias con la expresión regular y reemplaza todas menos la primera con la cadena vacía. La expresión regular coincide con un carácter que ya aparece una vez en la cadena, lo que significa que se mantendrán los dos primeros.



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

K4 está disponible para descarga gratuita ; K6 está en desarrollo . Si ha descargado KDB, puede ingresar a K con barra invertida .

Puede ser más fácil ver esto dividido, pero primero una sintaxis: se g:xestablece gen x. {x+1}es una función que toma un argumento x . En K, el primer argumento para una función es x(el segundo esy y el tercero esz . No necesita un cuarto).

Ahora:

x:"aaabcbccdbabdcd"

=xsignifica grupo x , que produce:

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

2#'significa dos tomados (de) cada uno que produce

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

Como puede ver, estos son los desplazamientos de las dos primeras coincidencias de cada personaje. los 2 podrían ser generalizados.

,/significa unirse a cada uno y a menudo se llama raze . Nos dará los valores de nuestro diccionario. Por lo tanto, ,/"abcd"!(0 1;3 5;4 6;8 12)produce:

0 1 3 5 4 6 8 12

que debemos clasificar {x@<x}@es un idioma que los programadores de K a menudo ven (Q lo llama asc ), que dice x al subir de grado x . Rompiéndolo aparte:

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

devolvió los índices de la matriz ordenada, que queremos tomar de la matriz original. x@ysignifica x en y así que esto indexa la matriz con los índices del tipo (si eso tiene sentido).

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

que simplemente indexamos ahora en nuestra matriz original. Nosotros podríamos decir x@aquí, pero K es compatible con un concepto muy potente, que podemos aprovechar aquí: aplicación de función es la indexación. Eso significa que a[0]podría estar buscando la ranura cero de ao podría estar aplicando el 0a la función llamada a. La razón por la que necesitábamos @anteriormente {x@<x}es porque x<ysignifica xs menos que ys : los operadores en K tienen una forma diádica (dos argumentos) y una forma monádica (un argumento) que proviene de APL. Q no tiene esta "ambivalencia".


Bienvenido a PPCG! Gran primera respuesta. :)
Martin Ender

Tengo un par de preguntas. 1. ¿Es K4 el mismo idioma con el que se vincula (Q / kdb +)? 2. ¿Podría mostrar cómo llamar a su función en una entrada o cómo se deben formatear los elementos en testVectors.txt?
Dennis

@ Dennis 1. Sí. Presione la barra invertida para pasar de Q a K. 2. Tal como aparecen en la pregunta: ejemplo de pastebin.com/ftHe0bpE llame:g"aaabcbccdbabdcd"
geocar

Vale gracias. No se pudo hacer funcionar la parte del archivo, pero g"..."funciona. Desafortunadamente, su código vuelve aabbccpara la entrada abc.
Dennis

@ Dennis Es posible que hayas hecho algo mal: {x{?x@<x}@,/2#'=x}"abc"definitivamente regresa "abc". Volvería "aabbcc"si te perdieras lo ?distinto.
geocar


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;}

Versión sin golf:

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;
    }
}

Crea una matriz para todos los caracteres ascii. Si se produce un personaje, el contador correspondiente aumentará. Si es superior a 2, el carácter no se agregará a la cadena de resultados. Muy fácil, muy corto;)


2

Perl 6, 27 bytes

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

Explicación:

{.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: Perl 6 no está tan "orientado al golf" como su hermana Perl 5 ... Entonces sí, ese espacio antes de que <sea ​​necesario. %.{}Es un 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

Bienvenido a ppcg! Bonito primer post!
Rɪᴋᴇʀ

1

Lisp común, 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)

Bonito estampado

(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

Esto es bastante difícil de manejar, pero no estoy seguro de poder jugar golf mucho mejor en este momento. Cualquier sugerencia de golf es bienvenida. Pruébalo en línea!

Editar: -17 bytes gracias a Value Ink al sugerir una forma más golfista de eliminar los caracteres triplicados. -5 bytes de eliminar el .uniqmétodo.

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

Sin golf:

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 el

1

JavaScript, 30 bytes

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

Usando el método que @ edc65 ideó para contar pero con un filtro de matriz. La primera vez que aparece el carácter, el valor del objeto se vuelve "indefinido" más el carácter (es decir, "undefinedx"). La próxima vez que el valor del objeto se convierta en "undefinedxx".

Después de eso, v [x] [11] devuelve verdadero y cuando se combina con el operador no, falso, lo que significa que los caracteres que ya han aparecido dos veces se filtrarán.


0

Javascript (usando una biblioteca externa) (80 bytes)

Esta fue una buena! No gané pero fue divertido

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

Enlace a lib: https://github.com/mvegh1/Enumerable/

Explicación del código: el método acepta una cadena, la biblioteca la analiza como una matriz de caracteres y la cláusula Where es un predicado de filtrado complejo que verifica la presencia del carácter actual del hashmap 'a'. Si existe, incremente el contador, si no, ajústelo a 1. Si <2, el predicado (y el carácter actual) pasa, de lo contrario falla

ingrese la descripción de la imagen aquí


Se puede evitar el uso de una return, sino de hacer su función de una lista separada por comas de una de las expresiones entre paréntesis: n=>(a={},_From(n)....). La última expresión es el valor de retorno. En su Wherefunción, se puede eliminar la intermedia bpor completo mediante la comparación contra el resultado de la cesión o de la subasta: x=>(a[x]?a[x]++:a[x]=1)<2.
apsillers

Por último, se puede evitar el uso de una biblioteca externa en absoluto (y ahorrar bytes) utilizando los puntos suspensivos cadena de split y filtercon join: [...n].filter(...).join(""). Voltee la lógica verdadero / falso al cambiar Wherea filter.
apsillers

Ahh buenas observaciones!
Examinaré

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.

Pruébalo en línea!

Explicación:

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.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.