El combinador de cuerdas FizzBuzz-ish

25

Digamos que tienes una cadena como esta:

abaabbbbbaabba

Cuente el número de veces que aparece un carácter específico en la cadena de entrada, pero solo si el carácter aparece solo una vez en una fila . Por ejemplo, si el personaje es a,

abaabbbbbaabba
^ x      x   ^

El total sería 2 (el aa's no contaría porque aaparece dos veces seguidas).

¿Cómo se relaciona esto con FizzBuzz?

Si el personaje aparece 3 (o un múltiplo de 3) veces seguidas, o 5 (o un múltiplo de 5) veces seguidas, el contador se decrementa en su lugar. Si es un múltiplo de 3 y 5 veces, el contador aún se incrementa. Recuerde que el contador también se incrementa si el personaje aparece solo una vez en una fila, y se ignora si el personaje aparece cualquier otra cantidad de veces en una fila (además de las situaciones descritas anteriormente).

Para recapitular, si la cadena a unir es a,

input            counter (explanation)

a                 1 (single occurence)
aaa               -1(multiple of 3)
aaaaa             -1(multiple of 5)  
aaaaaaaaaaaaaaa   1 (multiple of 15)
aa                0 (none of the above)

aba               2 (two single instances)
aaba              1 (one single occurence(+1) and one double occurence(ignored))
aaaba             0 (one single occurence(+1) and one triple (-1)
aaaaaa            -1 (six is a multiple of three)

Implementación de referencia (sin golf) en java:

import java.util.Scanner;
import java.util.regex.*;

public class StrMatcher {

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in); //Scanner to get user input
        int total = 0;//Running total of matches

        System.out.println("Enter a string: ");
        String strBeingSearched = sc.nextLine(); //String that will be searched

        System.out.println("Enter string to match with: ");
        String strBeingMatched = sc.nextLine(); //Substring used for searching

        //Simple regex matcher
        Pattern pattern = Pattern.compile("(" + strBeingMatched + ")+");
        Matcher matcher = pattern.matcher(strBeingSearched);

        while(matcher.find()){  //While there are still matches

            int length = matcher.end() - matcher.start();
            int numberOfTimes = length/strBeingMatched.length();//Calculate how many times in a row the string is matched

            if((numberOfTimes == 1)||((numberOfTimes % 3 == 0) && (numberOfTimes % 5 == 0))){
                total++; //Increment counter if single match or divisible by 15
            } else if((numberOfTimes % 3 == 0)||(numberOfTimes % 5 == 0)) {
                total--; //Decrement counter if divisible by 3 or 5 (but not 15)
            }

            strBeingSearched = strBeingSearched.substring(matcher.end());
            matcher = pattern.matcher(strBeingSearched); //Replace string/matcher and repeat
        }

        System.out.println(total);
    }   
}
  • La cadena que se buscará puede tener cualquier longitud, pero el patrón solo será un carácter.
  • Ninguna cadena tendrá caracteres especiales regex.
  • Este es el ; el programa más corto en bytes gana.
  • No hay lagunas estándar.
Daniel M.
fuente
3
Sería útil si pudiera proporcionar algunos ejemplos de prueba más. Particularmente aquellos donde la secuencia tiene más de una letra.
Reto Koradi
Agregué algunos casos, con suerte eso ayudará. Dígame si necesito más casos, es mi primera vez en PPCG.
Daniel M.
Cambiaré los requisitos para que la secuencia sea solo un carácter, ya que la implementación es más o menos la misma, pero menos confusa.
Daniel M.
Esto es como la pregunta escasa 1 pero con la adición de FizzBuzz
ev3commander

Respuestas:

32

Funciton , 1840 bytes

Maldición, este lenguaje es ingobernable.

Este programa espera que el primer carácter de la entrada sea el carácter para buscar, y el resto de la entrada para hacer que la cadena busque. Esto significa que aaababuscará aen la entrada aaba(y, por lo tanto, en la salida 1). Usted puede separarlos con un salto de línea o espacio ( a aaba), pero sólo porque el salto de línea / espacio extra no hace ninguna diferencia a la salida.

Como siempre, puede obtener una representación más bonita (sin el espacio entre líneas) si ejecuta $('pre').css('line-height',1)en la consola de su navegador.

      ┌───┐
      │╓─╖└─────────────┐
      └╢³╟┐    ┌─────┐ ┌┴┐╓─╖
┌─────┐╙─╜└────┤┌─╖ ┌┴╖│┌┘║¹║
│     ├───────┐└┤²╟─┤·╟┘│ ╙┬╜╔═══════╗
│    ┌┴╖╔═╗┌─╖├┐╘╤╝ ╘╤╝┌┘  └┬╢2097151║
│    │♭║║5╟┤%╟┘└─┴──┐│┌┘┌───┘╚═══════╝
│    ╘╤╝╚═╝╘╤╝╔═╗┌─╖│││┌┴┐┌────┐
│    ┌┴╖   ┌┘ ║3╟┤%╟┘││└┬┘│╔══╗└┐
│  ┌─┤·╟─┐ │  ╚═╝╘╤╝ │└┐  │║21╟┐│
│  │ ╘╤╝ ├─┘┌─────┘  └┐└┐ │╚══╝│└─┐
│ ┌┴╖┌┴╖┌┴╖┌┴╖┌─╖    ┌┴╖│ │┌─╖┌┴─╖│
│┌┤·╟┤?╟┤?╟┤?╟┤+╟────┤³║│ └┤²╟┤>>║└──┐
││╘╤╝╘╤╝╘╤╝╘╤╝╘╤╝    ╘╤╝│  ╘╤╝╘╤═╝╓─╖│
││ │ ┌┴╖┌┴╖┌┴╖┌┴╖╔═╗ ┌┴╖│  ┌┴╖ ├──╢²╟┤
││ └─┤·╟┤·╟┤?╟┤·╟╢1║┌┤·╟┘  │♯║┌┴╖ ╙─╜│
│└──┐╘╤╝╘╤╝╘╤╝╘╤╝╚═╝│╘╤╝   ╘╤╝│¹║┌───┘
└──┐│╔╧╗ └┬─┘ ┌┴╖   │┌┴─╖   │ ╘╤╝│
   ││║1║ ┌┴┐┌─┤?╟───┴┤>>╟┐ ┌┴╖┌┴╖│
   ││╚═╝ └┬┘│ ╘╤╝    ╘══╝│┌┤?╟┤=║│
   │└────┐│╔╧╗     ┌─────┘│╘╤╝╘╤╝│
╔═╗└────┐│├╢0║╔══╗┌┴╖┌─╖ ╔╧╗   └─┘
║ ║     │└┘╚═╝║21╟┤×╟┤♯╟┐║0║
╚╤╝     └──┐  ╚══╝╘═╝╘═╝│╚═╝
 │┌──┴────╖└────────────┘
 ││int→str║
 │╘══╤════╝
┌┴─╖┌┴╖┌─╖╔╗
│>>╟┤³╟┤¹╟╢║
╘═╤╝╘═╝╘═╝╚╝
╔═╧╗
║21║
╚══╝

(1840 bytes cuando se codifica como UTF-16.)

Explicación

  • ¹ devuelve el primer caracter de una cadena.
  • ²cuenta el número de apariciones de un carácter al comienzo de una cadena dada. Por ejemplo, dado el carácter ay la cadena aaba, devuelve 2. For ay baa, devuelve 0.
  • ³llama ²para obtener el número de caracteres al inicio, examina si el número es divisible por 3 y 5 y si es igual a 1 y determina el incremento / decremento adecuado. También elimina un carácter adicional desde el inicio de la cadena (por ejemplo, dado aaabbaque elimina 3 + 1 = 4 caracteres, dando ba). Luego se llama recursivamente con la cadena más corta y agrega el resultado.
  • El programa principal llama ¹para eliminar el primer carácter de la entrada y llama ³con ese carácter y el resto de la cadena como argumentos separados.
Timwi
fuente
10
Nunca votaré por Funciton.
orlp
14

CJam, 40 36 35 32 30 bytes

0llcf=e`::*{(_g+Y13515Yb+=(+}/

¡Gracias a @ MartinBüttner por jugar golf en 1 byte!

¡Gracias a @AndreaBiondo por jugar 2 bytes y allanar el camino para 3 más!

Pruébelo en línea en el intérprete de CJam .

Cómo funciona

0          e# Push a 0 (accumulator).
l          e# Read a line from STDIN.
lc         e# Read a second line and keep only the first character.
f=         e# Check each character from the first line for equality.
           e# This results in 1 for the specified character and 0 for others.
e`         e# Perform run-length encoding.
::*        e# Multiply each element by its number of repetitions.
{          e# For each remaining integer I:
  (_!      e#   Subtract 1, copy and push sign(I-1).
  +        e#   Add the results.
           e#     If I == 0, I-1 + sign(I-1) =  -1 + -1 = -2.
           e#     If I == 1, I-1 + sign(I-1) =   0 +  0 =  0.
           e#     If I >= 2, I-1 + sign(I-1) = I-1 +  1 =  I.
  Y        e#   Push 2.
  13515Yb  e#   Convert 13515 into the array of its binary digits.
  +        e#   Concatenate 2 and the array.
           e#   This pushes [2 1 1 0 1 0 0 1 1 0 0 1 0 1 1].
  =        e#   Retrieve the digit at (index I-1 + sign(I-1))%15.
           e#     If I == 0, this pushes 1.
           e#     Else, if I == 1, this pushes 2.
           e#     Else, if I%15 == 0, this pushes 2.
           e#     Else, if I%3==0 or I%5==0, this pushes 0.
           e#     Else, this pushes 1.
  (        e#   Decrement the result.
  +        e#   Add it to the accumulator.
}/         e#
Dennis
fuente
Puede guardar otros 2 bytes con una tabla de búsqueda codificada en base e indexación modular: llcf=e`::*0-{(_!\6563282Zb:(=}%1bes 33 bytes.
Andrea Biondo
@AndreaBiondo Eso realmente ahorró 3 bytes. ¡Gracias!
Dennis
7

C, 160 126 125 119 114 109 104 100 bytes

main(int q,char **z){int i=0,t=0,s=0,a=z[1][0],c;do{if((c=z[2][i])!=a){s+=(!!t)*((t==1)-!(t%3)-!(t%5)+3*!(t%15));t=0;}else{++t;}++i;}while(c);printf("%d\n",s);}

Probablemente se puede mejorar ... Esto toma información de los argumentos de la línea de comando (el primer argumento es el patrón, el segundo es la cadena). No admite la búsqueda de patrones de caracteres NULL (\ x00).

EDITAR ** 126 125 119 114 109 104 100 bytes **: Después de incorporar las sugerencias de Dennis y algunas ideas adicionales (eliminada la cláusula else, combinó el while en una sola declaración y usó la resta en lugar de! =). También se eliminó el punto y coma extra en el bucle for (que en realidad era parte de la sugerencia de Dennis). Se acortó aún más al eliminar las variables 'i' y 'a'.

t,s;main(c,z)char**z;{for(;c;t++)if((c=*z[2]++)-*z[1])s+=!!t*((t<2)-!(t%3)-!(t%5)+3*!(t%15)),t=-1;printf("%d",s);}

Se eliminaron los operadores if y negación ('!') Al abusar del operador ternario. Comprimió las comprobaciones de modularidad usando ese 'AND' bit a bit un doble && porque bitwise '&' tiene un error, y colocando la comparación (t <2) dentro de los operadores ternarios. Reemplazado !! t * (...) moviendo !! t al operador ternario, lo que me permite eliminar paréntesis.

Hombre, realmente quiero ponerlo debajo de la marca de 100 bytes: S

t,s;main(c,z)char**z;{for(;c;)(c=*z[2]++)-*z[1]?s+=t%15?t%3&&t%5?t<2:-1:!!t,t=0:t++;printf("%d",s);}

Soluciones provisionales: No estoy seguro de si estas se considerarían válidas, pero puedo bajar a 93 caracteres si uso exit (s) en lugar de printf ("% d", s). Pero entonces la salida no sería visible, sino que sería un código de retorno. Si la salida es realmente necesaria, también puedo reducirla a 98 bytes, pero también requeriría imprimir todos los valores intermedios de s antes de la respuesta final ...

Tob Ernack
fuente
3
¡Bienvenido a Programming Puzzles & Code Golf! No lo he probado a fondo, pero i,t,s,a;main(c,z)char**z;{a=*z[1];while(c){if((c=z[2][i])!=a)s+=(!!t)*((t<2)-!(t%3)-!(t%5)+3*!(t%15)),t=0;else++t;++i;}printf("%d",s);}debería funcionar igual de bien (y es 23 bytes más corto).
Dennis
¡Oh, qué agradable es convertir la cláusula if () {} en una sola declaración!
Tob Ernack
Unos pocos bytes más: si comienzas maincon for(a=*z[1];c;i++), no necesitas {}el if ... else.
Dennis
4

Ruby, 111103 96 bytes

->s,m{s.chars.chunk{|x|x}.reduce(0){|x,(c,g)|l=g.size
x+(c!=m ?0:l<2||l%15<1?1:l%3*l%5<1?-1:0)}}

Este desafío fue hecho para Ruby Enumerable#chunk, así que tuve que publicar esto. :)

Prueba en línea: http://ideone.com/pG4mAn

El código es bastante sencillo. Aquí hay una versión más legible: http://ideone.com/ub3siA .

Cristian Lupascu
fuente
4

Python 3, 361, 300, 296, 263, 256, 237, 229, 188, 178 , 164 bytes.

Guardado 15 bytes gracias a vaultah de SOPython.
Guardado 9 bytes gracias a Joe Kington de SOPython.
Guardado 11 bytes gracias a DSM de SOPython.

Esta es la primera vez que envío una respuesta, así que estoy seguro de que esto podría ser mucho más corto. Toma la cadena de prueba como la primera respuesta a la entrada y el carácter de búsqueda como la segunda.

t=input()
m=input()
c=u=0
g=iter(t)
while g:
 r=next(g,0)
 if r==0:print(c);g=0
 while r==m:u+=1;r=next(g,0)
 if u:b=u%3<1;v=u%5<1;c+=((0,-1)[b|v],1)[u<2or b&v];u=0

Versión sin golf:

import sys
test = sys.argv[1]
match_char = sys.argv[2]
counter = char_counter = 0
char_generator = (c for c in test)
while char_generator:
    try:
        char = next(char_generator)
    except StopIteration:
        print(counter)
        break
    while char == match_char:
        char_counter += 1
        try:
            char = next(char_generator)
        except StopIteration:
            break
    if char_counter == 0:
        continue
    counter += 1 if char_counter == 1 or (char_counter % 3 == 0 and char_counter % 5 == 0) else -1 if char_counter % 3 == 0 or char_counter % 5 == 0 else 0
    char_counter = 0

Descubrí que estaba fallando en uno de los casos de prueba.

Morgan Thrapp
fuente
3

Haskell, 120 bytes

import Data.List
f c=sum.map(v.length).filter((==c).head).group
v 1=1
v n|n%3&&n%5=1|(n%3||n%5)=(-1)|0<1=0
x%y=x`mod`y<1

f hace el trabajo.

Leif Willerts
fuente
3

Java, 146 152 143 138 139 136 bytes

  1. Se corrigió un error.
  2. operaciones desplazadas, cambiadas a operador bit a bit para las %3&%5comprobaciones.
  3. i<2Comparación acortada .
  4. Se corrigió un error (la %3&%5comprobación no funciona como se pensaba).
  5. Se usó el método abreviado de multiplicación como se ve en la respuesta Ruby de @ w0lf .

Implementado como BiFunction<String, String, Integer>en Java 8, avíseme si es necesario que sea un programa completo (o si incluso puedo eliminar el java.util.regexprefijo del paquete a continuación).

El recuento de bytes anterior no incluye la nueva línea a continuación, que simplemente se agrega para fines de formateo en este sitio.

(a,b)->java.util.regex.Pattern.compile("[^"+b+"]").splitAsStream(a)
.mapToInt(v->v.length()).map(i->i<2?i:i%15<1?1:i%3*i%5<1?-1:0).sum();

Explicación aproximada:

  1. Aplicar expresiones regulares con un patrón que no coincida b, es decir "[^"+b+"]".
  2. Obtenga la longitud de cada ficha (por ejemplo "a" -> 1).
  3. Aplique la asignación deseada a -1, 0y 1.
  4. sum() para obtener respuesta
hjk
fuente
2

Javascript, 206 bytes

function f(n,e){var t=n.match(new RegExp(e,"g")).length,g=n.match(new RegExp(e+"{2,}","g"));return null!==g&&g.forEach(function(n){t-=n.length,n.length%15==0?t+=1:(n.length%3==0||n.length%5==0)&&(t-=1)}),t}

Expandido:

function funkyFizzb(n, c) {
    var score = n.match(new RegExp(c, "g")).length; 
    var repeatOccurence = n.match(new RegExp(c + "{2,}", "g"));

    if(repeatOccurence !== null) {
        repeatOccurence.forEach(function(v,i){
            // remove multiple occurrence counts
            score -= v.length;

            if(v.length % 15 == 0) {
                score += 1;
            }

            else if(v.length % 3 == 0 || v.length % 5 == 0) {
                score -= 1;
            }
        });
    }

    return score;
};

Explicación:

Estoy usando expresiones regulares para contar el total de veces que aparece un personaje, luego restar de eso todas las veces que apareció en grupos. Finalmente, reviso los grupos y hago el incremento / decremento del zumbido efervescente.

Pasa los casos de prueba dados en la pregunta:

funkyFizzb("aaa", "a") => -1

y así

lo digo en serio
fuente
Elimine new, use en execlugar de matchy alias length, y debería ser bueno.
Mama Fun Roll
2

Perl, 82 65 63 59 bytes

58 bytes + 1 byte parámetro de línea de comando

No es particularmente corto, pero es un comienzo, continuará acortándolo.

$l=y///c,$i+=!($l>1&&$l%15)||-!($l%3*$l%5)for/$^I+/g;$_=$i

Asumir que -ise puede usar para dar a la cadena de entrada un ejemplo de uso es el siguiente:

echo "aaabaaa" | perl -pi"a" entry.pl
Jarmex
fuente
0

Pyth, 32 bytes

¡tan cerca! 2 bytes más para vincular la excelente entrada de Dennis en CJam

s.b?qYz?tN@+,0_1 1+}3PN}5PN1Zrw8

Pruébelo en línea

Brian Tuck
fuente
0

gawk, 140

p=$2{b="[^"$1"]";for($0=2;$i-->0;){sub("^"b"*",_,p);p=substr(p,$++i=match(p,b))}for($i=length(p);$++j;)s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1}$0=s""

Ingrese como "cadena de espacio de caracteres", así

echo "x axxbxcxdexxxfffghixxj" | awk 'p=$2{b="[^"$1"]";for($0=2;$i-->0;){sub("^"b"*",_,p);p=substr(p,$++i=match(p,b))}for($i=length(p);$++j;)s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1}$0=s""'

Sin golf

p=$2{
    #i=j=s=0                # make reusable
    b="[^"$1"]";           # pattern "not matching char"
    $0=2;                  # help starting the while loop
    while($i-->0){         # match didn't return -1; dec stack top
        sub("^"b"*",_,p);  # remove not matching chars at head of string
        $++i=match(p,b);   # push index of first occurence of not matching char
        p=substr(p,$i)     # remove matching chars from head of string
    };
    $i=length(p);          # get last value
    while($++j)            # sometimes last value on stack is 0
        s+=$j%5?$j%3?$j<2:-1:$j%3?-1:1

        # if $j%5!=0
        #   if $j%3!=0     (not divisible by 5 AND 3)
        #     s+=($j==1)   (single character)
        #   else           (divisible by 3 but not by 5)
        #     s-=1
        # else             (divisble by 5)
        #   if $j%3!=0
        #     s-=1         (divisible by 5 but not by 3)
        #   else
        #     s+=1         (divisible by 3 AND 5)

}$0=s"" # output
Cabbie407
fuente
0

Pyth, 27 bytes

sm|!JPdx,02+}3J}5JhMf}zTrw8

Banco de pruebas

Ingrese en el formulario, por ejemplo:

a
aaaba

Explicación:

sm|!JPdx,02+}3J}5JhMf}zTrw8
                               z = input() (The match character)
                         w     input() (The string)
                        r 8    Run length encode
                    f}zT       Filter for the runs z is in.
                  hM           Take their lengths
 m|                            Map (d) to the logical or of
    Pd                         Find all prime factors of the current run length
   J                           Save them in J
  !                            Take the logical negation. This will be 1 if
                               d is 1, and 0 otherwise.
           +}3J                If d wasn't 1, add up 1 if 3 is in J
               }5J             and 1 if 5 is in J.
       x,02                    Then, take the index of the result in [0,2]
                               so 0 -> 0, 2 -> 1, 1 -> -1 (not found)
s                              Sum up the values for each run.
isaacg
fuente