Unico è economico


93

Scrivi una funzione o un programma che determina il costo di una determinata stringa, dove

  • il costo di ciascun personaggio è uguale al numero di volte in cui il personaggio si è verificato fino a questo punto nella stringa e
  • il costo della stringa è la somma dei costi dei suoi caratteri.

Esempio

Per un input di abaacab, il costo viene calcolato come segue:

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

Pertanto, il costo per la stringa abaacabè 14.

Regole

  • Il punteggio del tuo invio è il costo del tuo codice come definito sopra , ovvero il tuo invio viene eseguito sul suo codice sorgente, con un punteggio inferiore migliore.
  • L'invio deve funzionare su stringhe contenenti caratteri ASCII stampabili, oltre a tutti i caratteri utilizzati nell'invio.
  • I personaggi sono case-sensitive, cioè ae Asono caratteri diversi.

Casi test

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

Classifica


2
In che modo vengono -nconteggiati i punteggi del programma come Perl per il punteggio? Conta tradizionalmente come 1 byte perché la distanza di modifica tra lo standard perl -eed perl -neè 1, ma per questa sfida, il nconteggio ai fini del conteggio dei duplicati?
Value Ink

2
@ValueInk Sì, penso che contare nsia l'opzione più giusta.
Laikoni,

1
Vorrei davvero che ci fosse una soluzione geniale a questa sfida.
Peter1807,

10
+1 per Il punteggio della tua presentazione è il costo del tuo codice
luizfzs,

1
il costo di un personaggio è definito come how often this character has already occurred in the string, probabilmente cambierei per how many times the character has occurred up to this pointchiarire che il primo utilizzo costa 1, non 0
undergroundmonorail

Risposte:


83

MATL , punteggio 4

&=Rz

Provalo online!

Spiegazione

Considera l'input 'ABBA'come esempio.

&=   % 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

14
Sei un professore di algebra lineare?
Magic Octopus Urn,

4
@carusocomputing In realtà un professore di comunicazioni mobili. La mia tendenza a usare le matrici proviene da anni di programmazione in Matlab
Luis Mendo il

Neat! Matlab è grande in quella zona? Non ho mai veramente guardato al GSM o qualcosa del genere.
Magic Octopus Urn,

2
Mi sono unito a questa community solo per lodarti su questa brillante soluzione!
Wboy,

1
@carusocomputing Matlab è uno strumento / linguaggio molto comune in ingegneria in generale. È bravo nel calcolo numerico: algebra lineare, elaborazione del segnale e simili. Ed essendo un linguaggio interpretato è molto facile da usare
Luis Mendo,

17

Python , punteggio 49

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

Provalo online!

C'è una scheda dopo in.

Analisi del punteggio:

  • +27 per 27 caratteri unici
  • +16 per 8 caratteri doppi: ()Camnou
  • +6 per 1 carattere triplicato: S

13
Utilizzare una scheda anziché uno spazio per salvare un byte.
mbomb007,

1
@ mbomb007 Ho avuto la stessa idea :-)
xnor

1
@ mbomb007 Hah, è un trucco geniale :-)
ETHproductions

14
@ mbomb007 questo è solo un tab contro la guerra degli spazi all'interno del codice golf
Erik the Outgolfer,

2
Stavo per suggerire di usare un feed di modulo (che è anche permesso spazi bianchi nella sintassi di Python), ma non hai più spazi bianchi da sostituire.
user2357112

8

T-SQL, punteggio 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

EDIT : abbandonato un paio di variabili, compattato un po '. Fino a 16 @simboli invece di 22, questo da solo riduce il mio punteggio di ben 117 punti!

Simpatico contest, mi piace la necessità di ottimizzare qualcosa oltre al conteggio totale dei personaggi.

L'ingresso è tramite varchar campo q nella tabella preesistente z , per le nostre regole IO . Il database contenente questa tabella di input deve essere impostato su regole di confronto sensibili al maiuscolo / minuscolo .

formattato:

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

Le parole chiave SQL non fanno distinzione tra maiuscole e minuscole, quindi ho usato il caso misto per ridurre al minimo il numero di lettere duplicate ( aaAA genera un punteggio migliore / inferiore rispetto a aaaa ).

Il ciclo principale confronta la lunghezza prima e dopo aver rimosso tutte le istanze del primo carattere. Quella differenza n * (n + 1) / 2 viene aggiunta a un totale parziale.

La LEN()funzione SQL ignora fastidiosamente gli spazi finali, quindi ho dovuto aggiungere un carattere di controllo e sottrarre 1 alla fine.

EDIT : risolto un errore di calcolo del mio punteggio di 2 punti (problema con virgolette), ridotto di 1 cambiando il case di uno R. Lavorando anche su una strategia completamente diversa, pubblicherò questa come una propria risposta.


3
All'inizio pensavo che il tuo punteggio fosse579! ≈ 8.22 x 10^1349
Ingegnere Toast,

8

C (gcc) , punteggio:  113  103 100   96  91

Grazie a @ugoren, @CalculatorFeline, @gastropner, @ l4m2 e @ JS1 per i loro suggerimenti.

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

Inizializza una matrice di zeri, quindi utilizza i valori ASCII dei caratteri nella stringa come indici di quella matrice per tenere traccia del numero di istanze di ciascun carattere nella stringa.

Provalo online!


3
Suggerimento: Utilizzare i nomi delle variabili che non vengono utilizzati in parole chiave, come z, x, c.
Calcolatrice

@CalculatorFeline charinclude c...
Neil,

3
Inoltre, hai solo bisogno di un array di 127 elementi ( \x7fnon stampabile) e aggiungi una spiegazione.
Calcolatrice

1
In ritardo alla festa, ma questo dovrebbe essere 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), punteggio 81 78

Hai salvato 3 punti grazie a @Arnauld

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

La mia soluzione ricorsiva score-81 originale:

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



7

Retina , punteggio 34

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

Provalo online!

Spiegazione

s(O`.

Iniziamo ordinando tutti i caratteri nell'input in modo che i caratteri identici siano raggruppati in un'unica sequenza. L' s(attiva modalità singleline per tutte le fasi (cioè fa .coi linefeeds).

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

L'obiettivo è quello di trasformare una sequenza di n caratteri in T n caratteri (il n -esimo numero triangolare), perché questo è il punteggio delle occorrenze di questo personaggio. Per fare ciò, troviamo corrispondenze sovrapposte. In particolare, per ogni i in [1, n] , includeremo i personaggi i-1 nella partita. Riceviamo tutte quelle partite a causa della bandiera sovrapposta &. Questo ci dà n * (n-1) / 2 = T n-1 = T n - n caratteri solo dalle partite. Ma la fase della partita si unirà a queste con gli avanzamenti di riga, che sono n gli avanzamenti di riga per nle partite. C'è solo un problema. Non ci sarà un avanzamento di riga dopo l'ultima partita, quindi il numero complessivo di caratteri nell'output è uno in meno del necessario. Risolviamo questo adattando anche l'inizio dell'input, il che ci dà un singolo avanzamento di riga se c'è almeno un'altra corrispondenza.

.

Infine, contiamo solo quanti caratteri ci sono nella stringa.


6

Haskell, punteggio 52 51

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

C'è una scheda tra fe _.

Provalo online!

Il valore della stringa vuota è 0. Il valore della stringa s, dove aè il primo carattere e bil resto della stringa è 1 più le occorrenze di ain bpiù una chiamata ricorsiva con b.


5

J , punteggio 16

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

Provalo online!

Spiegazione

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.

Usando 1#.invece che +/@per la somma si salvano alcuni punti e si &possono usare invece che @in un contesto monadico per salvarne uno in più. Il ripetuto 1mi costa un punto in più, ma non sono riuscito a liberarmene.


"later" aspetta un quarto di giorno
CalculatorFeline

2
@CalculatorFeline 10 ore dopo è ancora più tardi. : P
Zgarb,

Facciamo un sesquisemiday ora.
Calcolatrice

Personalmente uso questo formato per le risposte TIO al fine di riflettere un conteggio accurato di byte nella sezione del codice, forse vorresti usarlo
Conor O'Brien,

5

R , punteggio: 67 83 95 128

-61 grazie ai migliori consigli di Giuseppe

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

Provalo online!

La stringa viene divisa usando utf8ToInte viene contato ogni valore ASCII table. Il risultato viene calcolato usando una moltiplicazione di matrice %*%su quella a sé + 1 e infine dimezzata.


usa tableinvece di rle; puoi anche sbarazzartene sort(e non devi indicizzare [[1]]il risultato di strsplit)
Giuseppe

@Giuseppe Grazie mille. Non ho nemmeno pensato al tavolo, lo incorporerò presto.
MickyT,

2
Penso che puoi salvare qualche byte in più usando un nome di variabile diverso invece di n(dato che è in functiondue volte) e anche cambiando (n+1)in{n+1}
Giuseppe,

punteggio: 67 . Alcune variazioni su questo potrebbero consentire di ridurre ulteriormente il punteggio.
Giuseppe,

@Giuseppe ... avrei dovuto rileggerlo. whoops
MickyT


4

Pyth , punteggio 6

1 byte grazie a isaacg.

+F/V._

Suite di test.

Come funziona

+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.

s+0è lo stesso di +F.
isaacg,

Buono! Il meglio che potrei fare è usaShHGrScQ1 8Zper 16. Puoi aggiungere una spiegazione?
Digital Trauma,

1
@DigitalTrauma Ho aggiunto una spiegazione.
Leaky Nun,

s/LQè il punteggio 4, utilizza funzionalità che postdatano la sfida?
Dave,


4

Jelly , punteggio di 7

ċЀQRFS

Spiegazione:

   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)

Provalo online!


2
Benvenuti in PPCG!
Laikoni,

4

C, 60 byte, punteggio 108 95

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

Provalo online!

Di solito gli operatori pre e post-incremento sono fantastici per il golf del codice, ma fanno davvero male a questa sfida!

EDIT: Sottraendo i conteggi negativi invece di aggiungere quelli positivi, ho salvato un sacco di punteggio. Sostituendo anche for()con while()un punto e virgola eliminato.



3

C # (.NET Core) , punteggio ∞ (Voglio dire, 209)

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

Provalo online!

Il punteggio include quanto segue:

using System.Linq;

So che è passato del tempo, ma puoi passare return w*(w+1)/2a return-~w*w/2(punteggio 196). EDIT: è possibile creare una porta della mia risposta Java 8 per un punteggio di 149 : using System.Linq;b=>{int[]x=new int[256];return\nb.Select(z=>++x[z]).Sum();} Provalo online.
Kevin Cruijssen,

1
@KevinCruijssen: ho ottenuto la tua soluzione fino a un punteggio di 111:b=>{var x=new int[256];return\nb.Sum(z=>++x[z]);}
raznagul

@raznagul ( * risposta di mezzo anno in arrivo * ) 109 se si modifica il secondo spazio in una scheda. ;) Provalo online.
Kevin Cruijssen,

1
@KevinCruijssen (un'altra risposta di mezzo anno in arrivo) 49 con il compilatore interattivo, e penso che non scenderà mai al di sotto di 48. Trovo strano quanto più ottengano le risposte C # giocate a golf, più leggibili sembrano sempre. Provalo online!
qualcuno il


3

PowerShell, punteggio 64

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

(Il punteggio si basa su una nuova riga di avanzamento riga, che non è standard di Windows ma funziona in PS).

PS C:\> D:\unique-is-cheap.ps1 (gc D:\unique-is-cheap.ps1 -raw)
64
  • Contatore Hashtable @{}
  • Scorrere le lettere; $argsè un array di parametri - in questo caso la stringa di input lo rende un array a singolo elemento; |%esegue un ciclo foreach sugli elementi e utilizza il getE*collegamento per abbinare il GetEnumerator()metodo stringa e chiamarlo per trasformare la stringa in un flusso di caratteri.
  • |%passa in rassegna i caratteri e incrementa la loro voce hashtable, aggiungila a un totale parziale. Il ($x+=1)modulo con parentesi modifica sia la variabile che genera il nuovo valore per l'uso.
  • Emette il totale parziale.

(Quando l'ho scritto per la prima volta, era $c=@{};$t=0;[char[]]"$args"|%{$c[$_]++;$t+=$c[$_]};$tcon un punteggio di 128 e mi sembrava che non sarebbe sceso molto più in basso. Dimezzarlo a 64 è abbastanza piacevole).


1
61 punti / 38 byte pasticciare con l'incremento
Veskah


3

Julia 0.6 , 45 byte, Punteggio: 77

Ispirato dalla soluzione MATL:

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

Provalo online!

Una soluzione meno carina, usando i conteggi:

Julia 0.6 , punteggio: 82

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

Provalo online!

Grazie a Guiseppe per aver sottolineato il punteggio e per i suggerimenti. Questi commenti mi hanno aiutato a caricare.


1
Il punteggio della tua richiesta è il costo del tuo codice , che penso sia 135.
Giuseppe

1
Non conosco molto bene Julia, ma penso che puoi ridurre il punteggio a 110 cambiando alcuni nomi di variabili e rimuovendo una serie di parentesi. Se è consentito restituire un vettore a elemento singolo, è possibile sostituirlo (x+1)con [x+1]per ridurre ulteriormente il punteggio.
Giuseppe

È possibile salvare un punteggio modificando il secondo spazio in una scheda o in una nuova riga: punteggio 104 . E @Giuseppe punta di usare [x+1]invece di (x+1)abbassarlo a un punteggio di 98 .
Kevin Cruijssen,

3

Java 10, punteggio: 149 138 137 134 133 130 103 102 101 100

( Byte: 72 73 74 75 64 62 61 ) I byte aumentano, ma il punteggio diminuisce. : D

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

-28 punteggio (e -11 byte) grazie a @Nevay .
-1 punteggio (e -2 byte) grazie a @ OlivierGrégoire .
-1 punteggio (e -1 byte) convertendo Java 8 in Java 10.

Spiegazione:

Provalo qui.

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

1
È possibile rimuovere il ~se si utilizza j=0e return-j;(133).
Nevay,

1
103:x->{int[]q=new int[256];return\nx.chars().map(v->++q[v]).sum();}
Nevay,

1
@Nevay 103 in realtà, quando uso jinvece di u( returncontiene u) e una nuova riga e una scheda anziché gli spazi. EDIT: Hehe, hai modificato proprio quando ho fatto questo commento. :)
Kevin Cruijssen,

3

F #, punteggio 120 118

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

-2 grazie a Kevin Cruijssen !

Provalo online!

Prende stringun input. Seq.countByaccoppia ogni carattere distinto con il suo conteggio ( idè la funzione identità) in modo da finire con una raccolta come 'a' = 4, 'b' = 2ecc.

Il Seq.sumByprende il conteggio per ogni lettera e riassume tutti i numeri da 0per il conteggio per quella lettera. Quindi, se 'a' = 4la collezione fosse quella 0, 1, 2, 3, 4che è stata sommata è 10. Quindi Seq.sumBysomma tutti quei totali.


2
Puoi abbassare il tuo punteggio di 2 cambiando let qin let j, poiché qè già utilizzato in entrambi Seq.
Kevin Cruijssen,

2

APL (Dyalog) , punteggio 15

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

Provalo online!

 ottenere input di testo

∘.=⍨ tabella di uguaglianza con se stessi

+\ somma cumulativa attraverso

1 1⍉ diagonale (lit. comprimi entrambe le dimensioni nella dimensione uno)

+/ somma


2

Retina , punteggio 68 45 43

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

Provalo online! Il link mostra il punteggio. Modifica: grazie a @MartinEnder che ha salvato 20 byte utilizzando corrispondenze sovrapposte anziché lookaheads e altri tre byte raggruppando le fasi in modo che il sflag debba essere applicato una sola volta. Salvati altri due byte calcolando il numero triangolare in modo diverso, evitando la necessità di un ordinamento.



2

Punteggio Perl 5 91 83

Usa il -pflag che aggiunge 2 a causa della p in split.

$x=$_;$b+=++$a{$_}for(split//,$x);$_=$b

Benvenuti in PPCG!
Laikoni,

1
Usando la tua risposta come base e applicando alcune tecniche dalla pagina dei suggerimenti, sono riuscito a ottenere il tuo punteggio fino a 31: provalo online! . $` is automatically print ed after each call so we can use that to store the score and /./ g` restituisce un elenco di tutti i caratteri in $_, che è più economico di split//.
Dom Hastings,

So che questa è una vecchia sfida, ma puoi tagliare ulteriormente il punteggio: provalo online!
Xcali,

2

Ottava , 39 byte, punteggio 69

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

Provalo online!

Mentre c'è un'altra risposta per Octave, questa è interamente mia e con un approccio diverso, inoltre ha un punteggio inferiore :).

L'approccio si riduce alla prima ricerca del conteggio (b) di ciascun carattere univoco, che si ottiene utilizzando la funzione istogramma. Quindi per ogni elemento calcoliamo la somma di 1 a b che viene eseguita utilizzando la formula (b*(b+1))/2. Quindi le singole somme vengono tutte sommate nel punteggio finale.

Nei test sembra che le parentesi siano davvero costose nel punteggio perché ne sono necessarie molte. Ho ottimizzato giù da un punteggio iniziale di circa 88 riorganizzando le domande per ridurre al minimo il numero di parentesi aperte / chiuse - quindi ora facciamo il / 2 sul totale finale piuttosto che individualmente, e ho anche modificato la formula in (b^2+b)/2poiché ciò richiede meno parentesi.


1
Sfortunatamente questo sembra fallire sulla stringa vuota:error: hist: subscript indices must be either positive integers less than 2^31 or logicals
Laikoni,

2

Lisp comune, punteggio 286 232 222

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

Punteggio di valore elevato a causa della prolassi sintassi degli operatori integrati di Common Lisp.

Provalo online!

Il codice ungolfed:

(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

2

Mathematica, punteggio 54

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

ingresso

[ "ABCDEFG"]

grazie a hftf


Total[#(#+1)/2&@Counts@Characters@#]&segna 54.
hftf
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.