Único es barato

93

Escriba una función o programa que determine el costo de una cadena dada, donde

  • el costo de cada carácter es igual al número de veces que el personaje ha ocurrido hasta este punto en la cadena, y
  • El costo de la cadena es la suma de los costos de sus personajes.

Ejemplo

Para una entrada de abaacab, el costo se calcula de la siguiente manera:

a b a a c a b
1   2 3   4    occurrence of a
  1         2  occurrence of b
        1      occurrence of c
1+1+2+3+1+4+2 = 14

Por lo tanto, el costo de la cadena abaacabes 14.

Reglas

  • La puntuación de su presentación es el costo de su código como se definió anteriormente , que es su presentación funcionar en su propio código fuente, con una menor puntuación de estar mejor.
  • Su envío debe funcionar en cadenas que contengan caracteres ASCII imprimibles, más todos los caracteres utilizados en su envío.
  • Los caracteres distinguen entre mayúsculas y minúsculas, es decir, ay Ason caracteres diferentes.

Casos de prueba

input -> output
"abaacab" -> 14
"Programming Puzzles & Code Golf" -> 47
"" -> 0
"       " -> 28
"abcdefg" -> 7
"aA" -> 2

Tabla de clasificación

Laikoni
fuente
2
¿Cómo -ncuentan los indicadores del programa como Perl para la puntuación? Tradicionalmente cuenta como 1 byte porque la distancia de edición entre el estándar perl -ey perl -nees 1, pero para este desafío, ¿ ncontará con el propósito de contar duplicados?
Value Ink
2
@ValueInk Sí, creo que contar nes la opción más justa.
Laikoni
1
Realmente desearía que hubiera una solución mental para este desafío.
Peter1807
10
+1 para El puntaje de su envío es el costo de su código
luizfzs
1
el costo de un personaje se define como how often this character has already occurred in the string, probablemente cambiaría para how many times the character has occurred up to this pointaclarar que el primer uso cuesta 1, no 0
undergroundmonorail

Respuestas:

83

MATL , puntaje 4

&=Rz

Pruébalo en línea!

Explicación

Considere la entrada 'ABBA'como un ejemplo.

&=   % Implicit input. Matrix of all equality comparisons
     % STACK: [1 0 0 1;
               0 1 1 0;
               0 1 1 0;
               1 0 0 1]
R    % Upper triangular part
     % STACK: [1 0 0 1;
               0 1 1 0;
               0 0 1 0;
               0 0 0 1]
z    % Number of nonzeros. Implicitly display
     % STACK: 6
Luis Mendo
fuente
14
¿Eres un profesor de álgebra lineal?
Magic Octopus Urn
44
@carusocomputing Actualmente profesor de comunicaciones móviles. Mi tendencia a usar matrices proviene de años de programación en Matlab
Luis Mendo
¡Ordenado! ¿Matlab es grande en esa área? Nunca he mirado realmente en GSM o algo así.
Magic Octopus Urn
2
¡Me uní a esta comunidad solo para felicitarte por esta brillante solución!
Wboy
1
@carusocomputing Matlab es una herramienta / lenguaje muy común en ingeniería en general. Es bueno para el cálculo numérico: álgebra lineal, procesamiento de señales y similares. Y siendo un lenguaje interpretado es muy fácil de usar
Luis Mendo
17

Python , puntaje 49

lambda S:sum(1+S.count(C)for[C]in	S)/2

Pruébalo en línea!

Hay una pestaña después in.

Desglose del puntaje:

  • +27 por 27 caracteres únicos
  • +16 por 8 caracteres dobles: ()Camnou
  • +6 por 1 carbón triplicado: S
xnor
fuente
13
Use una pestaña en lugar de un espacio para guardar un byte.
mbomb007
1
@ mbomb007 Acabo de tener la misma idea :-)
xnor
1
@ mbomb007 Ja, eso es un truco genial :-)
ETHproductions
14
@ mbomb007 eso es solo pestañas versus guerra espacial dentro del código de golf
Erik the Outgolfer
2
Iba a sugerir utilizar un feed de formulario (que también está permitido espacios en blanco en la sintaxis de Python), pero no tiene más espacios en blanco para reemplazar.
user2357112
8

T-SQL, puntuación 775 579! 580

declaRe @ char(876),@x int,@v int=0Select @=q+CHAR(9)from z X:seleCT @x=len(@),@=REPLACE(@,LEFT(@,1),''),@v+=(@x-LEN(@))*(@x-LEN(@)+1)/2IF LEN(@)>0GOTO X prINT @v-1

EDITAR : Se descartaron un par de variables, se compactaron un poco. ¡Hasta 16 @símbolos en lugar de 22, eso por sí solo reduce mi puntaje en la friolera de 117 puntos!

Bonito concurso, me gusta el requisito de optimizar para algo además del recuento total de personajes.

La entrada es a través del campo varchar q en la tabla z preexistente , según nuestras reglas de IO . La base de datos que contiene esta tabla de entrada debe establecerse en una intercalación entre mayúsculas y minúsculas .

Formateado:

declaRe @ char(876), @x int, @v int=0
Select @=q+CHAR(9)from z
X:
    seleCT @x=len(@)
          ,@=REPLACE(@,LEFT(@,1),'')
          ,@v+=(@x-LEN(@))*(@x-LEN(@)+1)/2
IF LEN(@)>0 GOTO X
prINT @v-1

Las palabras clave SQL no distinguen entre mayúsculas y minúsculas, por lo que utilicé mayúsculas y minúsculas para minimizar el recuento de letras duplicadas ( aaAA genera una puntuación mejor / menor que aaaa ).

El bucle principal compara la longitud antes y después de eliminar todas las instancias del primer carácter. Esa diferencia n * (n + 1) / 2 se agrega a un total acumulado.

La LEN()función SQL ignora molestamente los espacios finales, por lo que tuve que agregar un carácter de control y restar 1 al final.

EDITAR : Se corrigió un error de cálculo de mi propia puntuación en 2 puntos (problema con las citas entre comillas), reducido en 1 al cambiar la carcasa de uno R. También trabajando en una estrategia completamente diferente, lo publicaré como su propia respuesta.

BradC
fuente
3
Al principio pensé que tu puntaje era579! ≈ 8.22 x 10^1349
Engineer Toast
8

C (gcc) , puntuación:  113  103 100   96  91

Gracias a @ugoren, @CalculatorFeline, @gastropner, @ l4m2 y @ JS1 por sus consejos.

g(char*s){int y[238]={};while(*s)*y-=--y[*s++];*y/=1;}

Inicializa una matriz de ceros, luego usa los valores ASCII de los caracteres en la cadena como índices de esa matriz para realizar un seguimiento del número de instancias de cada carácter en la cadena.

Pruébalo en línea!

Steadybox
fuente
3
Sugerencia: Utilice nombres de variables que no se utilizan en palabras clave, como z, x, c.
CalculatorFeline
@CalculatorFeline charincluye c...
Neil
3
Además, solo necesita una matriz de 127 elementos ( \x7fno se puede imprimir) y agregue una explicación.
CalculatorFeline
1
Tarde a la fiesta, pero esto debería ser 96:z;g(char*s){int y[238]={z=0};while(*s)z+=--y[*s++];z/=~0;}
gastropner
1
g(char*s){int y[238]={};while(*s)*y+=--y[*s++];*y/=~0;}
l4m2
7

JavaScript (ES6), puntaje 81 78

Ahorró 3 puntos gracias a @Arnauld

s=>s.replace(d=/./g,z=>q+=d[z]=-~d[z],q=0)&&q

Mi solución recursiva original score-81:

f=([c,...s],d={})=>c?(d[c]=-~d[c])+f(s,d):0
ETHproducciones
fuente
7

Retina , puntaje 34

s(O`.
M&!`^|(?<=(.))\1*
.

Pruébalo en línea!

Explicación

s(O`.

Comenzamos clasificando todos los caracteres en la entrada para que los caracteres idénticos se agrupen en una sola ejecución. La s(activa el modo SingleLine para todas las etapas (es decir, hace .avances de línea de partido).

M&!s`^|(?<=(.))\1*

El objetivo es convertir a una racha de n caracteres en T n caracteres (el n ésimo número triangular) porque esa es la puntuación de las apariciones de este personaje. Para hacerlo, encontramos coincidencias superpuestas. En particular, para cada i en [1, n] , vamos a incluir caracteres i-1 en la coincidencia. Obtenemos todos esos partidos debido a la bandera superpuesta &. Eso nos da n * (n-1) / 2 = T n-1 = T n - n caracteres solo de las coincidencias. Pero la etapa de coincidencia los unirá con saltos de línea, que son n saltos de línea para npartidos. Solo hay un problema. No habrá un salto de línea después de la última coincidencia, por lo que el número total de caracteres en la salida es uno menos de lo que necesitamos. Arreglamos esto haciendo coincidir también el comienzo de la entrada, lo que nos da un salto de línea principal si hay al menos otra coincidencia.

.

Finalmente, solo contamos cuántos caracteres hay en la cadena.

Martin Ender
fuente
6

Haskell, puntaje 52 51

f(a:b)=1+sum[1|c<-b,c==a]+f b;f _=0

Hay una pestaña entre fy _.

Pruébalo en línea!

El valor de la cadena vacía es 0. El valor de la cadena s, donde aes el primer carácter y bel resto de la cadena es 1 más las apariciones de ain bmás una llamada recursiva con b.

nimi
fuente
5

J , puntaje 16

1#.,@(*+/\"1)&=

Pruébalo en línea!

Explicación

1#.,@(*+/\"1)&=
              =  Self-classify: bit matrix of equality between input
                 and its unique elements.
     (      )&   Apply verb in parentheses to it:
       +/\         running sums
          "1       of each row
      *            multiplied with original matrix.
                 This causes the i'th 1 on each row to be replaced by i.
   ,@            Flatten the resulting matrix
1#.              and interpret as a base-1 number, computing its sum.

Usar en 1#.lugar de +/@para la suma ahorró algunos puntos, y &podría usarse en lugar de @en un contexto monádico para guardar uno más. La repetición 1me cuesta un punto extra, pero no he podido deshacerme de él.

Zgarb
fuente
"más tarde" espera un cuarto de día
CalculatorFeline
2
@CalculatorFeline 10 horas más tarde aún es más tarde. : P
Zgarb
Hagámoslo un sesquisemiday ahora.
CalculatorFeline
Yo personalmente uso este formato para las respuestas de TIO para reflejar un recuento de bytes preciso en la sección del código, tal vez quieras usarlo
Conor O'Brien
5

R , puntuación: 67 83 95 128

-61 gracias a los mejores consejos de Giuseppe

function(x,y=table(utf8ToInt(x)))y%*%{y+1}/2

Pruébalo en línea!

La cadena se divide usando utf8ToInty se cuenta cada valor ASCII table. El resultado se calcula haciendo una multiplicación de matriz %*%sobre eso en sí mismo + 1 y finalmente se reduce a la mitad.

MickyT
fuente
usar en tablelugar de rle; también puedes deshacerte de él sort(y no tienes que indexar [[1]]el resultado strsplit)
Giuseppe
@Giuseppe Muchas gracias. Ni siquiera pensé en la mesa, la incorporaré pronto.
MickyT
2
Creo que puede guardar unos pocos bytes más utilizando un nombre de variable diferente en lugar de n(ya que está en functiondos veces) y también cambiando (n+1)a{n+1}
Giuseppe
puntuación: 67 . Alguna variación en esto podría permitir reducir aún más la puntuación.
Giuseppe
@Giuseppe ... Debería haberlo leído nuevamente. whoops
MickyT
4

Pyth , puntaje 6

1 byte gracias a isaacg.

+F/V._

Banco de pruebas.

Cómo funciona

+F/V._
+F/V._QQ  implicit input
  /V      vectorize count: for each element in the first argument,
                           count the number of occurrences of the
                           second argument:
    ._Q       all prefixes of input
       Q      input
+F        fold (reduce) on +, base case 0.
Monja permeable
fuente
s+0es el mismo que +F.
isaacg
¡Bueno! Lo mejor que puedo hacer es usaShHGrScQ1 8Zpor 16. ¿Puedes agregar una explicación?
Trauma digital
1
@ DigitalTrauma He añadido una explicación.
Leaky Nun
s/LQes el puntaje 4, ¿esto usa características que son posteriores al desafío?
Dave
4

J , puntuación: 14 12 11

$+/@,2!1#.=

Pruébalo en línea!

FrownyFrog
fuente
Uso inteligente de $.
cole
Agradable. Ligera variación de 11 bytes:1#.2!1+1#.=
Jonás
@Jonah Reutilizar los glifos resulta en una penalización
FrownyFrog
ah, perdí esa parte.
Jonás
4

Jalea , puntaje de 7

ċЀQRFS

Explicación:

   Q    get unique letters
ċЀ     count the occurences of each letter in the original string
    R   [1..n] for n in list of frequencies
     F  flatten list
      S sum
        (implicit output)

Pruébalo en línea!

ellie
fuente
2
Bienvenido a PPCG!
Laikoni
4

C, 60 bytes, puntaje 108 95

g(char*s){int y[256]={},z=0;while(*s)z-=--y[*s++];return z;}

Pruébalo en línea!

Por lo general, los operadores antes y después del incremento son excelentes para el golf de código, ¡pero realmente duelen en este desafío!

EDITAR: Al restar los recuentos negativos en lugar de sumar los positivos, ahorré un montón de puntaje. Reemplazar for()con while()eliminado un punto y coma también.

ErikF
fuente
3

Perl 6 , puntaje  61 56 53 46  44

(1 X..*.comb.Bag.values).flat.sum

Intentalo

{sum flat 1 X.. .comb.Bag.values}

Intentalo

{sum flat 1 X.. values(.comb.Bag)}

Intentalo

{[+] flat	1	X.. values(.comb.Bag)}

Intentalo

{[+] flat	1	X.. values(bag
.comb)}

Intentalo

Brad Gilbert b2gills
fuente
3

C # (.NET Core) , puntaje ∞ (quiero decir, 209)

b=>b.Distinct().Select(z=>{var w=b.Count(p=>p==z);return w*(w+1)/2;}).Sum()

Pruébalo en línea!

La puntuación incluye lo siguiente:

using System.Linq;
Charlie
fuente
Sé que ha pasado un tiempo, pero puedes cambiar return w*(w+1)/2a return-~w*w/2(puntaje 196). EDITAR: Puede crear un puerto de mi respuesta Java 8 para una puntuación de 149 : using System.Linq;b=>{int[]x=new int[256];return\nb.Select(z=>++x[z]).Sum();} Pruébelo en línea.
Kevin Cruijssen
1
@KevinCruijssen: Obtuve tu solución a una puntuación de 111:b=>{var x=new int[256];return\nb.Sum(z=>++x[z]);}
raznagul
@raznagul ( * respuesta de medio año entrante * ) 109 si cambia el segundo espacio a una pestaña. ;) Pruébalo en línea.
Kevin Cruijssen
1
@KevinCruijssen (otra respuesta de medio año entrante) 49 con el compilador interactivo, y creo que nunca será inferior a 48. Me resulta extraño cómo las respuestas de C # más golfizadas, más legibles siempre parecen ser. Pruébalo en línea!
alguien el
3

Jalea , puntaje 5

ĠJ€ẎS

Pruébalo en línea!

Gracias a Leaky Nun por -2 (anteriormente en su respuesta )

Erik el Outgolfer
fuente
Ahhh, no me di cuenta de esta pregunta lo suficientemente rápido.
Leaky Nun
@LeakyNun ps no siempre eres un ninja, ni nadie lo es
Erik the Outgolfer
De Verdad? No lo creo.
CalculatorFeline
Puntuación 5:ĠJ€ẎS
Leaky Nun
@LeakyNun Como se prometió ... sí, el crédito está ahí :)
Erik the Outgolfer
3

PowerShell, puntaje 64

$z=@{}
$ARGS|% getE*|%{$u+=($Z.$_+=1)};$U

(La puntuación se basa en una nueva línea de salto de línea, que no es estándar de Windows pero funciona en PS).

PS C:\> D:\unique-is-cheap.ps1 (gc D:\unique-is-cheap.ps1 -raw)
64
  • Contador hashtable @{}
  • Iterar a través de las letras; $argses una matriz de parámetros; en este caso, la cadena de entrada la convierte en una matriz de un solo elemento; |%realiza un bucle foreach sobre los elementos y utiliza el getE*acceso directo para hacer coincidir el GetEnumerator()método de cadena y llamarlo para convertir la cadena en una secuencia de caracteres.
  • |%recorrer los caracteres e incrementar su entrada de tabla hash, agregarlo a un total acumulado. El ($x+=1)formulario con parens modifica la variable y genera el nuevo valor para su uso.
  • Salida del total acumulado.

(Cuando lo escribí por primera vez, tenía $c=@{};$t=0;[char[]]"$args"|%{$c[$_]++;$t+=$c[$_]};$tun puntaje de 128, y sentí que no iría mucho más bajo. Reducirlo a 64 es bastante agradable).

TessellatingHeckler
fuente
1
61 pts / 38 bytes jugando con el incremento
Veskah
3

Julia 0.6 , 45 bytes, Puntuación: 77

Inspirado en la solución MATL:

f(w)=sum(UpperTriangular([z==j for z=w,j=w]))

Pruébalo en línea!

Una solución menos bonita, usando recuentos:

Julia 0.6 , puntuación: 82

F(w)=sum(l->[l+1]l/2,count(x->x==i,w)for i=Set(w))

Pruébalo en línea!

Gracias a Guiseppe por señalar la puntuación y por los consejos. Estos comentarios me ayudaron mucho.

niczky12
fuente
1
El puntaje de su presentación es el costo de su código , que creo que es 135.
Giuseppe
1
No conozco muy bien a Julia, pero creo que puedes reducir la puntuación a 110 cambiando algunos nombres de variables y eliminando un conjunto de paréntesis. Si se permite devolver un vector de un solo elemento, entonces se puede sustituir (x+1)con [x+1]reducir aún más el marcador.
Giuseppe
Puede guardar una puntuación cambiando el segundo espacio a una pestaña o una nueva línea: puntuación 104 . Y la sugerencia de uso de @Giuseppe en [x+1]lugar de reducirlo (x+1)a un puntaje de 98 .
Kevin Cruijssen
3

Java 10, puntuación: 149 138 137 134 133 130 103 102 101 100

( Bytes: 72 73 74 75 64 62 61 ) Los bytes suben, pero el puntaje baja. :RE

x->{int j=0,q[]=new int[256];for(var    C:x)j+=++q[C];return
j;}

-28 puntaje (y -11 bytes) gracias a @Nevay .
-1 puntuación (y -2 bytes) gracias a @ OlivierGrégoire .
-1 puntaje (y -1 byte) al convertir Java 8 a Java 10.

Explicación:

Pruébalo aquí.

x->{                     // Method with character-array parameter and integer return-type
  int j=0,               //  Result-integer, starting at 0
      q[]=new int[256];  //  Integer-array with 256 times 0
  for(var   C:x)         //  Loop over the characters of the input array
    j+=++q[C];           //   Raise the value in the array by 1,
                         //   and then add it to the result-integer
  return                 //  Return 
  j;}                    //         the result
Kevin Cruijssen
fuente
1
Puede eliminar el ~si usa j=0y return-j;(133).
Nevay
1
103:x->{int[]q=new int[256];return\nx.chars().map(v->++q[v]).sum();}
Nevay
1
@Nevay 103 en realidad, cuando uso en jlugar de u( returncontiene u) y una nueva línea y pestaña en lugar de los espacios. EDITAR: Jeje, has editado justo cuando hice este comentario. :)
Kevin Cruijssen
3

F #, puntaje 120 118

let j z=Seq.countBy id z|>Seq.sumBy(fun x->List.sum[0..snd x])

-2 gracias a Kevin Cruijssen !

Pruébalo en línea!

Toma a stringcomo entrada. Seq.countByempareja cada carácter distinto con su recuento ( ides la función de identidad) para que termines con una colección como 'a' = 4, 'b' = 2etc.

La Seq.sumBytoma del recuento para cada letra y resume todos los números de 0la cuenta para esa letra. Entonces, si 'a' = 4la colección sería la 0, 1, 2, 3, 4que sumada es 10. Luego Seq.sumBysuma todos esos totales.

Ciaran_McCarthy
fuente
2
Puede reducir su puntaje en 2 cambiando let qa let j, ya que el qya se usa en ambos Seq.
Kevin Cruijssen
2

APL (Dyalog) , puntaje 15

+/1 1⍉+\∘.=⍨⍞

Pruébalo en línea!

 obtener entrada de texto

∘.=⍨ tabla de igualdad con uno mismo

+\ suma acumulativa a través de

1 1⍉ diagonal (iluminado. contraiga ambas dimensiones en la dimensión uno)

+/ suma

Adán
fuente
2

Retina , puntaje 68 45 43

s`(.)(?<=((\1)|.)+)
$#3$*
1

Pruébalo en línea! El enlace muestra la puntuación. Editar: Gracias a @MartinEnder que ahorró 20 bytes al usar coincidencias superpuestas en lugar de lookaheads y otros tres bytes al agrupar las etapas para que la sbandera solo se aplique una vez. Ahorró otros dos bytes calculando el número triangular de manera diferente, evitando la necesidad de una clasificación.

Neil
fuente
2

Perl 5 puntaje 91 83

Utiliza la -pbandera que agrega 2 debido a la p en la división.

$x=$_;$b+=++$a{$_}for(split//,$x);$_=$b
usuario1937198
fuente
Bienvenido a PPCG!
Laikoni
1
Utilizando su respuesta como base y aplicando algunas técnicas de la página de consejos, logré reducir su puntaje a 31: ¡ Pruébelo en línea! . $` is automatically print ed after each call so we can use that to store the score and /./ g` devuelve una lista de todos los caracteres en $_, que es más barato que split//.
Dom Hastings
Sé que este es un viejo desafío, pero puedes reducir aún más el puntaje: ¡ Pruébalo en línea!
Xcali
2

Octava , 39 bytes, puntaje 69

@(a)sum((b=hist(a,unique(1*a))).^2+b)/2

Pruébalo en línea!

Si bien hay otra respuesta de Octave, esta es completamente mía y tiene un enfoque diferente, además, obtiene menos puntajes :).

El enfoque se reduce a encontrar primero el recuento (b) de cada carácter único, que se logra utilizando la función de histograma. Luego, para cada elemento, calculamos la suma de 1 a b que se realiza utilizando la fórmula (b*(b+1))/2. Luego, las sumas individuales se suman en la puntuación final.

En las pruebas, parece que los corchetes son realmente costosos en la calificación porque se necesitan muchos. He optimizado desde un puntaje inicial de aproximadamente 88 al reorganizar las preguntas para minimizar el número de paréntesis de apertura / cierre; por lo tanto, ahora hacemos el / 2 en el total final en lugar de individualmente, y también he modificado la fórmula para (b^2+b)/2ya que requiere menos paréntesis.

Tom Carpenter
fuente
1
Desafortunadamente, esto parece fallar en la cadena vacía:error: hist: subscript indices must be either positive integers less than 2^31 or logicals
Laikoni
2

Common Lisp, puntaje 286 232 222

(loop with w =(fill(make-list 128)0)as z across(read)sum(incf(elt w(char-code z))))

Puntaje de alto valor debido a la sintaxis verbal de los operadores integrados de Common Lisp.

Pruébalo en línea!

El código sin golf:

(loop with w = (fill (make-list 128) 0)  ; create a list to count characters
   as z across (read)                   ; for each character of input
   sum (incf (elt w (char-code z))))     ; increase count in list and sum
Renzo
fuente
2

Mathematica, puntaje 54

Total[#(#+1)/2&@Counts@Characters@#]&

entrada

["abcdefg"]

gracias a hftf

J42161217
fuente
Total[#(#+1)/2&@Counts@Characters@#]&puntajes 54.
hftf