Único é barato

93

Escreva uma função ou programa que determine o custo de uma determinada string, em que

  • o custo de cada caractere é igual ao número de vezes que o caractere ocorreu até esse ponto na sequência e
  • o custo da string é a soma dos custos de seus caracteres.

Exemplo

Para uma entrada de abaacab, o custo é calculado da seguinte forma:

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

Assim, o custo da cadeia abaacabé 14.

Regras

  • A pontuação do seu envio é o custo do seu código, conforme definido acima , ou seja, seu envio é executado em seu próprio código-fonte, com uma pontuação menor sendo melhor.
  • Seu envio deve funcionar com seqüências contendo caracteres ASCII imprimíveis, além de todos os caracteres usados ​​no envio.
  • Os personagens são case-sensitive, isto é ae Asão personagens diferentes.

Casos de teste

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

Entre os melhores

Laikoni
fonte
2
Como os sinalizadores de programa, como o -nPerl, contam para a pontuação? Tradicionalmente conta como 1 byte, porque a distância de edição entre o padrão perl -ee perl -neé 1, mas para esse desafio, a ncontagem será contada com o objetivo de contar duplicatas?
Value Ink
2
@ ValueInk Sim, acho que contar né a opção mais justa.
Laikoni
1
Eu realmente gostaria que houvesse uma solução cerebral para esse desafio.
precisa saber é o seguinte
10
+1 para A pontuação do seu envio é o custo do seu código
luizfzs
1
custo de um personagem é definido como how often this character has already occurred in the string, eu provavelmente iria mudar para how many times the character has occurred up to this pointtorná-lo mais claro que os primeiros custos de utilização 1, não 0
undergroundmonorail

Respostas:

83

MATL , pontuação 4

&=Rz

Experimente online!

Explicação

Considere a entrada 'ABBA'como um exemplo.

&=   % 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
fonte
14
Você é um professor de álgebra linear?
Magic Octopus Urn
4
@carusocomputing Na verdade, é professor de comunicações móveis. Minha tendência a usar matrizes vem de anos de programação em Matlab
Luis Mendo
Arrumado! O Matlab é grande nessa área? Eu nunca realmente gostei de GSM ou algo assim.
Magic Octopus Urn
2
Entrei para esta comunidade apenas para elogiá-lo por esta solução brilhante!
Wboy
1
@carusocomputing O Matlab é uma ferramenta / linguagem muito comum na engenharia em geral. É bom em computação numérica: álgebra linear, processamento de sinais e similares. E sendo uma linguagem interpretada, é muito fácil de usar
Luis Mendo
17

Python , pontuação 49

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

Experimente online!

Há uma guia depois in.

Classificação da pontuação:

  • +27 por 27 caracteres únicos
  • +16 por 8 caracteres duplos: ()Camnou
  • +6 por 1 caractere triplo: S
xnor
fonte
13
Use uma guia em vez de um espaço para salvar um byte.
mbomb007
1
@ mbomb007 Apenas teve a mesma idéia :-)
xnor
1
@ mbomb007 Hah, isso é um :-) truque gênio
ETHproductions
14
@ mbomb007 que está apenas guias guerra contra espaços dentro golfed código
Erik as Outgolfer
2
Eu sugeriria o uso de um feed de formulário (que também é permitido espaço em branco na sintaxe do Python), mas você não tem mais espaço em branco para substituir.
user2357112
8

T-SQL, pontuação 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 : Soltou algumas variáveis, compactou um pouco. Até 16 @símbolos em vez de 22, isso por si só reduz minha pontuação em 117 pontos!

Bom concurso, eu gosto do requisito de otimizar algo além da contagem total de caracteres.

A entrada é via campo varchar q na tabela z pré-existente , de acordo com nossas regras de IO . O banco de dados que contém esta tabela de entrada deve ser definido como um agrupamento que diferencia maiúsculas de minúsculas .

Formatado:

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

As palavras-chave SQL não diferenciam maiúsculas de minúsculas, por isso usei maiúsculas e minúsculas para minimizar a contagem de letras duplicadas ( aaAA gera uma pontuação melhor / menor que aaaa ).

O loop principal compara o comprimento antes e depois de remover todas as instâncias do primeiro caractere. Essa diferença n * (n + 1) / 2 é adicionada ao total em execução.

A LEN()função SQL irrita irritantemente os espaços à direita, então tive que acrescentar um caractere de controle e subtrair 1 no final.

EDIT : Corrigido um erro de cálculo da minha própria pontuação em 2 pontos (problema com as aspas), reduzido em 1 ao alterar a caixa de um R. Também trabalhando em uma estratégia completamente diferente, postarei isso como sua própria resposta.

BradC
fonte
3
No começo eu pensei que sua pontuação fosse579! ≈ 8.22 x 10^1349
Engineer Toast
8

C (gcc) , pontuação:  113  103 100   96  91

Obrigado a @ugoren, @CalculatorFeline, @gastropner, @ l4m2 e @ JS1 pelas dicas.

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

Inicializa uma matriz de zeros e, em seguida, usa os valores ASCII dos caracteres na sequência como índices para essa matriz para acompanhar o número de instâncias de cada caractere na sequência.

Experimente online!

Steadybox
fonte
3
Sugestão: Use nomes de variáveis que não são usados em palavras-chave, como z, x, c.
CalculatorFeline
@CalculatorFeline charinclui c...
Neil
3
Além disso, você só precisa de uma matriz de 127 elementos ( \x7fnão é imprimível) e adicione uma explicação.
CalculatorFeline
1
Tarde para a festa, mas deve ser 96:z;g(char*s){int y[238]={z=0};while(*s)z+=--y[*s++];z/=~0;}
gastropner 15/03
1
g(char*s){int y[238]={};while(*s)*y+=--y[*s++];*y/=~0;}
l4m2
7

JavaScript (ES6), pontuação 81 78

Guardado 3 pontos graças a @Arnauld

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

Minha solução recursiva original score-81:

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

Haskell , pontuação 42

f l=sum[1|c<-l,d<-c:l,d==c]/2

Experimente online!

Anonimizar \l->dá a mesma pontuação.

xnor
fonte
7

Retina , pontuação 34

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

Experimente online!

Explicação

s(O`.

Começamos classificando todos os caracteres na entrada para que caracteres idênticos sejam agrupados em uma única execução. A s(ativa o modo Singleline para todas as fases (ou seja, faz .linefeeds jogo).

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

O objetivo é transformar uma corrida de n caracteres em T n caracteres (o n º número triangular) porque essa é a pontuação das ocorrências desta natureza. Para fazer isso, encontramos correspondências sobrepostas. Em particular, para cada i em [1, n] , vamos incluir caracteres i-1 na partida. Recebemos todas essas correspondências devido à bandeira sobreposta &. Isso nos dá n * (n-1) / 2 = T n-1 = T n - n caracteres apenas das correspondências. Mas a fase de partida juntará esses itens aos feeds de linha, que são n feeds de linha para nfósforos. Só tem um problema. Não haverá avanço de linha após a última correspondência, portanto, o número total de caracteres na saída é um a menos do que precisamos. Corrigimos isso combinando também o início da entrada, o que nos fornece um único avanço de linha principal se houver pelo menos uma outra correspondência.

.

Finalmente, contamos apenas quantos caracteres existem na string.

Martin Ender
fonte
6

Haskell, pontuação 52 51

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

Há uma guia entre fe _.

Experimente online!

O valor da cadeia vazia é 0. O valor da cadeia s, onde aé o primeiro caractere e bo restante da cadeia é 1 mais as ocorrências de ain bmais uma chamada recursiva com b.

nimi
fonte
5

J , pontuação 16

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

Experimente online!

Explicação

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 em 1#.vez de +/@para a soma economizou alguns pontos e &poderia ser usado em vez de @em um contexto monádico para salvar mais um. O repetido 1me custa um ponto extra, mas não consegui me livrar dele.

Zgarb
fonte
"later" espera um quarto de dia
CalculatorFeline
2
@CalculatorFeline 10 horas depois ainda é mais tarde. : P
Zgarb
Vamos fazer uma sexta-feira agora.
CalculatorFeline
Eu pessoalmente uso este formato de respostas TIO, a fim de refletir uma contagem de bytes precisas na seção de código, talvez você gostaria de usá-lo
Conor O'Brien
5

R , pontuação: 67 83 95 128

-61 graças às principais dicas de Giuseppe

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

Experimente online!

A cadeia é dividida usando utf8ToInte cada valor ascii é contado table. O resultado é calculado usando uma multiplicação de matrizes %*%sobre isso em si + 1 e, finalmente, metade.

MickyT
fonte
use em tablevez de rle; você pode se livrar do sortbem (e você não tem o índice [[1]]para o resultado de strsplit)
Giuseppe
@ Giuseppe Muito obrigado. Eu nem pensei em mesa, vou incorporar em breve.
MickyT
2
Eu acho que você pode economizar mais alguns bytes usando um nome de variável diferente em vez de n(uma vez que é em functionduas vezes) e também mudando (n+1)para{n+1}
Giuseppe
pontuação: 67 . Alguma variação nisso pode permitir reduzir ainda mais a pontuação.
Giuseppe
@ Giuseppe ... eu deveria ter re ler. whoops
MickyT
4

Pyth , pontuação 6

1 byte graças a isaacg.

+F/V._

Suíte de teste.

Como 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.
Freira Furada
fonte
s+0é o mesmo que +F.
Isaacg
Boa! O melhor que posso fazer é usaShHGrScQ1 8Zpor 16. Você pode adicionar uma explicação?
Digital Trauma
1
@DigitalTrauma Adicionei uma explicação.
precisa
s/LQé a pontuação 4, isso usa recursos que pós-datam o desafio?
Dave
4

J , pontuação: 14 12 11

$+/@,2!1#.=

Experimente online!

FrownyFrog
fonte
Uso inteligente de $.
cole
Agradável. Ligeira variação de 11 bytes:1#.2!1+1#.=
Jonah
@Jonah Reutilizar glifos resulta em penalidade
FrownyFrog
ah, perdi essa parte.
Jonah
4

Geléia , pontuação 7

ċЀQRFS

Explicação:

   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)

Experimente online!

ellie
fonte
2
Bem-vindo ao PPCG!
Laikoni 23/01
4

C, 60 bytes, pontuação 108 95

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

Experimente online!

Normalmente, os operadores de pré e pós-incremento são ótimos para o golfe de código, mas realmente prejudicam esse desafio!

Edição: subtraindo contagens negativas em vez de adicionar positivas, salvei um monte de pontuação. Substituindo for()por while()eliminou um ponto-e-vírgula também.

ErikF
fonte
3

Perl 6 , pontuação  61 56 53 46  44

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

Tente

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

Tente

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

Tente

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

Tente

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

Tente

Brad Gilbert b2gills
fonte
3

C # (.NET Core) , pontuação ∞ (quero dizer, 209)

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

Experimente online!

A pontuação inclui o seguinte:

using System.Linq;
Charlie
fonte
Eu sei que já faz um tempo, mas você pode mudar return w*(w+1)/2para return-~w*w/2(pontuação 196). EDIT: Você pode criar uma porta da minha resposta Java 8 para obter uma pontuação de 149 : using System.Linq;b=>{int[]x=new int[256];return\nb.Select(z=>++x[z]).Sum();} Experimente online.
Kevin Cruijssen
1
@KevinCruijssen: Eu tenho a sua solução reduzida para uma pontuação de 111:b=>{var x=new int[256];return\nb.Sum(z=>++x[z]);}
raznagul 15/03/18
@raznagul ( * resposta de meio ano de entrada * ) 109 se você alterar o segundo espaço para uma guia. ;) Experimente online.
Kevin Cruijssen 21/09
1
@KevinCruijssen (mais uma resposta de meio ano recebida) 49 com o compilador interativo e acho que nunca chegará a menos de 48. Acho estranho como as respostas C # mais eficientes são obtidas, mais legíveis elas sempre parecem. Experimente online!
alguém
3

Geléia , pontuação 5

ĠJ€ẎS

Experimente online!

Obrigado a Leaky Nun por -2 (anteriormente em sua resposta )

Erik, o Outgolfer
fonte
Ahhh, eu não percebi essa pergunta rápido o suficiente.
Freira vazada
@LeakyNun ps nem sempre é um ninja, nem ninguém é
Erik o Outgolfer
Realmente? Acho que não.
CalculatorFeline
Pontuação 5:ĠJ€ẎS
Leaky Nun
@LeakyNun Como prometido ... Sim, o crédito está lá :)
Erik o Outgolfer
3

PowerShell, pontuação 64

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

(A pontuação é baseada em uma nova linha de alimentação de linha única, que não é padrão do Windows, mas funciona no PS).

PS C:\> D:\unique-is-cheap.ps1 (gc D:\unique-is-cheap.ps1 -raw)
64
  • Contador Hashtable @{}
  • Iterar através das letras; $argsé uma matriz de parâmetros - nesse caso, a string de entrada a torna uma única matriz de itens; |%faz um loop foreach sobre os itens e usa o getE*atalho para corresponder ao GetEnumerator()método string e chame-o para transformar a string em um fluxo de caracteres.
  • |%faça um loop sobre os caracteres e aumente sua entrada de hashtable, adicione-a ao total em execução. O ($x+=1)formulário com parens modifica a variável e gera o novo valor para uso.
  • Saída do total em execução.

(Quando o escrevi pela primeira vez, era $c=@{};$t=0;[char[]]"$args"|%{$c[$_]++;$t+=$c[$_]};$tcom uma pontuação de 128 e parecia que não iria diminuir muito. Reduzir para 64 é bastante agradável).

TessellatingHeckler
fonte
1
61 pts / 38 bytes , mexendo com o incremento
Veskah em 3/01
59 pts / 36 bytes
mazzy 29/04
3

Julia 0.6 , 45 bytes, Pontuação: 77

Inspirado na solução MATL:

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

Experimente online!

Uma solução menos bonita, usando contagens:

Julia 0.6 , pontuação: 82

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

Experimente online!

Agradecemos a Guiseppe por apontar a pontuação e obter dicas. Esses comentários me ajudaram muito.

niczky12
fonte
1
A pontuação de sua submissão é o custo de seu código , que eu acho que é 135.
Giuseppe
1
Não conheço Julia muito bem, mas acho que você pode reduzir a pontuação para 110 alternando alguns nomes de variáveis ​​e removendo um conjunto de parênteses. Se o retorno de um vetor de elemento único for permitido, você poderá substituí-lo (x+1)por [x+1]para reduzir ainda mais a pontuação.
Giuseppe
Você pode salvar uma pontuação alterando o segundo espaço para uma guia ou nova linha: pontuação 104 . E @ Giuseppe dica de usar em [x+1]vez de (x+1)reduz para uma pontuação de 98 .
Kevin Cruijssen
3

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

( Bytes: 72 73 74 75 64 62 61 ) Os bytes aumentam, mas a pontuação diminui. : D

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

Pontuação de -28 (e -11 bytes) graças a @Nevay .
-1 pontos (e -2 bytes) graças a @ OlivierGrégoire .
-1 pontuação (e -1 byte) convertendo o Java 8 em Java 10.

Explicação:

Experimente aqui.

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
fonte
1
Você pode remover o ~se você usar j=0e return-j;(133).
Nevay 14/09/17
1
103:x->{int[]q=new int[256];return\nx.chars().map(v->++q[v]).sum();}
Nevay
1
@Nevay 103, na verdade, quando uso em jvez de u( returncontém u) e uma nova linha e guia em vez dos espaços. EDIT: Hehe, você editou quando fiz este comentário. :)
Kevin Cruijssen
3

F #, pontuação 120 118

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

-2 graças a Kevin Cruijssen !

Experimente online!

Tira a stringcomo entrada. Seq.countByemparelha cada caractere distinto com sua contagem ( idé a função de identidade) para que você termine com uma coleção como 'a' = 4, 'b' = 2etc.

Ele Seq.sumBypega a contagem para cada letra e soma todos os números da 0contagem para essa letra. Portanto, se 'a' = 4a coleção seria o 0, 1, 2, 3, 4que é somado em conjunto 10. Em seguida, Seq.sumBysoma todos esses totais.

Ciaran_McCarthy
fonte
2
Você pode diminuir sua pontuação em 2, alterando let qpara let j, pois o qjá é usado em ambos Seq.
Kevin Cruijssen
2

APL (Dyalog) , pontuação 15

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

Experimente online!

 obter entrada de texto

∘.=⍨ tabela de igualdade com auto

+\ soma acumulada entre

1 1⍉ diagonal (lit. recolher duas dimensões na dimensão um)

+/ soma

Adão
fonte
2

Retina , pontuação 68 45 43

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

Experimente online! O link mostra a pontuação. Editar: obrigado a @MartinEnder que salvou 20 bytes usando correspondências sobrepostas em vez de lookaheads e mais três bytes agrupando os estágios para que o ssinalizador precise ser aplicado apenas uma vez. Economizou mais dois bytes calculando o número triangular de maneira diferente, evitando a necessidade de uma classificação.

Neil
fonte
2

Perl 5 pontos 91 83

Usa a -pbandeira que adiciona 2 por causa de p na divisão.

$x=$_;$b+=++$a{$_}for(split//,$x);$_=$b
user1937198
fonte
Bem-vindo ao PPCG!
Laikoni
1
Usando sua resposta como base e aplicando algumas técnicas da página de dicas, consegui diminuir sua pontuação para 31: Experimente online! . $` is automatically print ed after each call so we can use that to store the score and /./ g` retorna uma lista de todos os caracteres $_, mais baratos que split//.
Dom Hastings
Sei que esse é um desafio antigo, mas você pode reduzir ainda mais a pontuação: experimente online!
Xcali # 13/18
2

Oitava , 39 bytes, Pontuação 69

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

Experimente online!

Embora exista outra resposta do Oitava, essa é totalmente minha e tem uma abordagem diferente, além de ter uma pontuação menor :).

A abordagem se resume a encontrar primeiro a contagem (b) de cada caractere único, que é alcançado usando a função de histograma. Então, para cada elemento, calculamos a soma de 1 a b, que é feita usando a fórmula (b*(b+1))/2. Em seguida, as somas individuais são todas somadas na pontuação final.

Nos testes, parece que os colchetes são realmente caros na pontuação, porque muitos são necessários. Otimizei a partir de uma pontuação inicial de cerca de 88, reorganizando as perguntas para minimizar o número de colchetes de abrir / fechar - portanto, agora fazemos o / 2 no total final em vez de individualmente, e também modifiquei a fórmula para (b^2+b)/2pois isso requer menos colchetes.

Tom Carpenter
fonte
1
Infelizmente, isso parece falhar na cadeia de caracteres vazia:error: hist: subscript indices must be either positive integers less than 2^31 or logicals
Laikoni
2

Lisp comum, pontuação 286 232 222

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

Pontuação de alto valor devido à sintaxe prolífica dos operadores internos do Common Lisp.

Experimente online!

O código não destruído:

(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
fonte
2

Mathematica, pontuação 54

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

entrada

["ABCDEFG"]

graças a hftf

J42161217
fonte
Total[#(#+1)/2&@Counts@Characters@#]&pontuação 54.
hftf 19/09/17