Unique est pas cher


93

Ecrivez une fonction ou un programme qui détermine le coût d’une chaîne donnée, où

  • le coût de chaque caractère est égal au nombre de fois où le caractère s'est produit jusqu'à ce point dans la chaîne, et
  • le coût de la chaîne est la somme des coûts de ses personnages.

Exemple

Pour une entrée de abaacab, le coût est calculé comme suit:

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

Ainsi, le coût de la chaîne abaacabest de 14.

Règles

  • Le score de votre soumission correspond au coût de votre code tel que défini ci - dessus , c'est-à-dire que votre soumission s'exécute sur son propre code source, un score inférieur étant meilleur.
  • Votre soumission doit fonctionner sur des chaînes contenant des caractères ASCII imprimables, ainsi que sur tous les caractères utilisés dans votre soumission.
  • Les caractères sont sensibles à la casse, c'est-à-dire aet Asont des caractères différents.

Testcases

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

Classement


2
Comment les indicateurs de programme tels que -nPerl comptent-ils dans le score? Il compte généralement pour 1 octet car la distance d'édition entre le standard perl -eet perl -ne1 est égale à 1, mais pour ce défi, le ndécompte sera-t-il pris en compte pour le comptage des doublons?
Valeur d'encre

2
@ValueInk Oui, je pense que compter l' noption la plus équitable.
Laikoni

1
Je souhaite vraiment qu'il y ait une solution brainfuck à ce défi.
Peter1807

10
+1 pour Le score de votre soumission est le coût de votre code
luizfzs

1
Le coût d'un personnage est défini comme suit how often this character has already occurred in the string: je changerais probablement pour how many times the character has occurred up to this pointpréciser que la première utilisation coûte 1, et non 0
undergroundmonorail

Réponses:


83

MATL , score 4

&=Rz

Essayez-le en ligne!

Explication

Considérez l'entrée 'ABBA'comme un exemple.

&=   % 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
Êtes-vous un professeur d'algèbre linéaire?
Urne Magic Octopus

4
@carusocomputing En réalité, professeur de communications mobiles. Ma tendance à utiliser des matrices provient d'années de programmation dans Matlab
Luis Mendo

Soigné! Matlab est-il grand dans ce domaine? Je n'ai jamais vraiment étudié le GSM ou quoi que ce soit du genre.
Urne magique Octopus

2
J'ai rejoint cette communauté juste pour vous recommander cette brillante solution!
Wboy

1
@carusocomputing Matlab est un outil / langage très courant en ingénierie en général. C'est bon pour le calcul numérique: algèbre linéaire, traitement du signal, etc. Et étant un langage interprété, il est très facile à utiliser
Luis Mendo

17

Python , score 49

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

Essayez-le en ligne!

Il y a un onglet après in.

Score score:

  • +27 pour 27 caractères uniques
  • +16 pour 8 caractères doubles: ()Camnou
  • +6 pour 1 caractère triplé: S

13
Utilisez un onglet au lieu d'un espace pour enregistrer un octet.
mbomb007

1
@ mbomb007 vient d'avoir la même idée :-)
xnor le

1
@ mbomb007 Hah, c'est un tour de génie :-)
ETHproductions

14
@ mbomb007 C'est juste la guerre entre les onglets et les espaces dans le code
du golf

2
J'allais suggérer d'utiliser un flux de formulaire (qui est également autorisé pour les espaces dans la syntaxe Python), mais vous n'avez plus d'espaces à remplacer.
user2357112

8

T-SQL, score 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 : laissé tomber quelques variables, compacté un peu. Avec 16 @symboles au lieu de 22, cela réduit mon score de 117 points!

Joli concours, j'aime l'exigence d'optimiser autre chose que le nombre total de caractères.

La saisie s'effectue via le champ varchar q de la table z préexistante , conformément à nos règles IO . La base de données contenant cette table d'entrée doit être définie sur un classement sensible à la casse .

Formaté:

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

Les mots-clés SQL ne sont pas sensibles à la casse. J'ai donc utilisé une casse mixte pour minimiser le nombre de lettres en double ( aaAA génère un score meilleur / inférieur à aaaa ).

La boucle principale compare la longueur avant et après suppression de toutes les occurrences du premier caractère. Cette différence n * (n + 1) / 2 est ajoutée à un total cumulé.

La LEN()fonction SQL ignore ennuyeusement les espaces de fin. Je devais donc ajouter un caractère de contrôle et soustraire 1 à la fin.

EDIT : Correction d'un calcul erroné de mon propre score de 2 points (problème de guillemets), réduit de 1 en changeant la casse d'un R. Travaillant également sur une stratégie complètement différente, je la publierai comme sa propre réponse.


3
Au début, je pensais que votre score était579! ≈ 8.22 x 10^1349
Ingénieur Toast

8

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

Merci à @ugoren, @CalculatorFeline, @gastropner, @ l4m2 et @ JS1 pour leurs conseils.

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

Initialise un tableau de zéros, puis utilise les valeurs ASCII des caractères de la chaîne en tant qu'indices de ce tableau pour suivre le nombre d'instances de chaque caractère de la chaîne.

Essayez-le en ligne!


3
Suggestion: Utilisez les noms de variables qui ne sont pas utilisés dans les mots - clés, comme z, x, c.
CalculatriceFeline

@CalculatorFeline charinclut c...
Neil

3
De plus, vous avez seulement besoin d'un tableau de 127 éléments ( \x7fnon imprimable) et ajoutez une explication.
CalculatriceFeline

1
En retard pour la fête, mais cela devrait être 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 le

7

JavaScript (ES6), score 81 78

A gagné 3 points grâce à @Arnauld

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

Ma solution récursive originale score-81:

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



7

Rétine , score 34

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

Essayez-le en ligne!

Explication

s(O`.

Nous commençons par trier tous les caractères de l’entrée afin que les caractères identiques soient regroupés en un seul passage. Le s(active le mode ligne unique pour toutes les étapes (c.-à-d .. Fait correspondre les sauts de ligne).

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

L'objectif est de transformer une série de n caractères en T n caractères (la n ième nombre triangulaire) parce que c'est le score des occurrences de ce caractère. Pour ce faire, nous trouvons des correspondances qui se chevauchent. En particulier, pour chaque i dans [1, n] , nous allons inclure les caractères i-1 dans la correspondance. Nous obtenons tous ces matches en raison du drapeau qui se chevauchent &. Cela nous donne n * (n-1) / 2 = T n-1 = T n - n caractères seulement des correspondances. Mais l’étape du match les rejoindra avec des sauts de ligne, qui sont n flux de ligne pour nallumettes. Il n'y a qu'un seul problème. Il n'y aura pas de saut de ligne après la dernière correspondance. Le nombre total de caractères dans la sortie est donc inférieur à celui dont nous avons besoin. Nous corrigeons cela en faisant également correspondre le début de l'entrée, ce qui nous donne un seul saut de ligne s'il y a au moins une autre correspondance.

.

Enfin, nous comptons simplement le nombre de caractères dans la chaîne.


6

Haskell, score 52 52 51

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

Il y a un onglet entre fet _.

Essayez-le en ligne!

La valeur de la chaîne vide est 0. La valeur de la chaîne s, où aest le premier caractère et ble reste de la chaîne est 1 plus les occurrences de ain bplus un appel récursif avec b.


5

J , note 16

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

Essayez-le en ligne!

Explication

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.

Utiliser 1#.au lieu de +/@pour la somme économise quelques points et &pourrait être utilisé au lieu de @dans un contexte monadique pour enregistrer un autre. La répétition 1me coûte un point de plus, mais je n'ai pas réussi à m'en débarrasser.


"plus tard" attend un quart
CalculatorFeline

2
@CalculatorFeline 10 heures plus tard, c'est encore plus tard. : P
Zgarb

Faisons-en un vendredi maintenant.
CalculatorFeline

Personnellement, j'utilise ce format pour les réponses TIO afin de refléter un nombre exact d'octets dans la section de code. Peut-être voudriez-vous l'utiliser
Conor O'Brien

5

R , score: 67 83 95 128

-61 grâce aux meilleurs conseils de Giuseppe

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

Essayez-le en ligne!

La chaîne est divisée en utilisant utf8ToIntet chaque valeur ASCII est comptée table. Le résultat est calculé en utilisant une multiplication matricielle %*%sur celle + 1 et finalement divisée par deux.


utiliser tableau lieu de rle; vous pouvez également vous en débarrasser sort(et vous n'avez pas à indexer [[1]]le résultat strsplit)
Giuseppe

@ Giuseppe Merci beaucoup. Je n'ai même pas pensé à la table, vais incorporer bientôt.
MickyT

2
Je pense que vous pouvez économiser quelques octets de plus en utilisant un nom de variable différent au lieu de n(puisqu'il est entré functiondeux fois) et en changeant également (n+1)pour{n+1}
Giuseppe

score: 67 . Certaines variations à cet égard pourraient permettre de réduire davantage le score.
Giuseppe

@ Giuseppe ... j'aurais dû relire. whoops
MickyT


4

Pyth , score 6

1 octet grâce à isaacg.

+F/V._

Suite de tests.

Comment ça fonctionne

+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+0est le même que +F.
isaacg

Bien! Le mieux que je puisse faire est usaShHGrScQ1 8Zde 16. Pouvez-vous ajouter une explication?
Digital Trauma

1
@ DigitalTrauma J'ai ajouté une explication.
Leaky Nun

s/LQest le score 4, cela utilise-t-il des fonctionnalités postérieures au défi?
Dave


4

Gelée , score de 7

ċЀQRFS

Explication:

   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)

Essayez-le en ligne!


2
Bienvenue chez PPCG!
Laikoni

4

C, 60 octets, score 108 95

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

Essayez-le en ligne!

Généralement, les opérateurs avant et après l’incrément sont parfaits pour le golf de code, mais ils font vraiment mal à ce défi!

EDIT: En soustrayant les comptes négatifs au lieu d’en ajouter des positifs, j’ai sauvé tout un tas de points. Remplacer for()par while()un point-virgule éliminé également.



3

C # (.NET Core) , score (je veux dire, 209)

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

Essayez-le en ligne!

Le score comprend les éléments suivants:

using System.Linq;

Je sais que ça fait longtemps, mais vous pouvez changer return w*(w+1)/2en return-~w*w/2(score 196). EDIT: Vous pouvez créer un portage de ma réponse Java 8 pour un score de 149 : using System.Linq;b=>{int[]x=new int[256];return\nb.Select(z=>++x[z]).Sum();} essayez-le en ligne.
Kevin Cruijssen

1
@KevinCruijssen: J'ai eu votre solution à un score de 111:b=>{var x=new int[256];return\nb.Sum(z=>++x[z]);}
raznagul

@raznagul ( * demi-année de réponse entrante * ) 109 si vous modifiez le deuxième espace en onglet. ;) Essayez-le en ligne.
Kevin Cruijssen le

1
@KevinCruijssen (une autre réponse d'un demi-an à venir) 49 avec le compilateur interactif, et je pense qu'il ne sera jamais inférieur à 48. Je trouve étrange de voir comment les réponses C # jouées au golf deviennent plus lisibles, elles semblent toujours devenir. Essayez-le en ligne!
quelqu'un


3

PowerShell, score 64

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

(Le score est basé sur un saut de ligne simple, ce qui n’est pas une norme Windows, mais fonctionne en mode PS).

PS C:\> D:\unique-is-cheap.ps1 (gc D:\unique-is-cheap.ps1 -raw)
64
  • Table de hachage @{}
  • Itérer à travers les lettres; $argsest un tableau de paramètres - dans ce cas, la chaîne d'entrée en fait un tableau à un seul élément; |%effectue une boucle foreach sur les éléments et utilise le getE*raccourci pour faire correspondre la GetEnumerator()méthode string et l'appeler pour transformer la chaîne en flux de caractères.
  • |%boucle sur les caractères et incrémenter leur entrée hashtable, l'ajouter à un total en cours d'exécution. Le ($x+=1)formulaire avec parent modifie à la fois la variable et génère la nouvelle valeur à utiliser.
  • Affiche le total cumulé.

(Quand je l'ai écrit pour la première fois, c'était $c=@{};$t=0;[char[]]"$args"|%{$c[$_]++;$t+=$c[$_]};$tavec un score de 128, et je pensais que ça ne baisserait pas beaucoup. Réduire de moitié le score à 64, c'est très agréable).


1
61 pts / 38 octets en jouant avec l'incrément
Veskah


3

Julia 0.6 , 45 bytes, Score: 77

Inspiré par la solution MATL:

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

Essayez-le en ligne!

Une solution moins jolie, en utilisant des comptes:

Julia 0.6 , score de 82

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

Essayez-le en ligne!

Merci à Guiseppe pour avoir souligné le pointage et les conseils. Ces commentaires m'ont aidé énormément.


1
Le score de votre soumission correspond au coût de votre code , qui est je pense de 135.
Giuseppe

1
Je ne connais pas très bien Julia mais je pense que vous pouvez réduire le score à 110 en changeant certains noms de variables et en supprimant un ensemble de parenthèses. Si le retour d'un vecteur à un seul élément est autorisé, vous pouvez le remplacer (x+1)par [x+1]pour réduire davantage le score.
Giuseppe

Vous pouvez enregistrer un score en modifiant le deuxième espace en onglet ou en nouvelle ligne: score 104 . Et @Giuseppe tip of use [x+1]au lieu de l' (x+1)abaisser à un score de 98 .
Kevin Cruijssen

3

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

( Octets: 72 73 74 75 64 62 61 ) Les octets montent, mais le score baisse. :RÉ

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

-28 score (et -11 octets) grâce à @Nevay .
-1 score (et -2 octets) grâce à @ OlivierGrégoire .
-1 score (et -1 octet) en convertissant Java 8 en Java 10.

Explication:

Essayez ici.

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
Vous pouvez supprimer le ~si vous utilisez j=0et 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 fait, quand j'utilise jau lieu de u( returncontient u) et une nouvelle ligne et un onglet au lieu des espaces. EDIT: Hehe, vous avez édité juste quand j'ai fait ce commentaire. :)
Kevin Cruijssen le

3

F #, score 120 118

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

-2 grâce à Kevin Cruijssen !

Essayez-le en ligne!

Prend un stringcomme une entrée. Seq.countByassocie chaque caractère distinct avec son compte ( idest la fonction identité) pour vous retrouver avec une collection comme 'a' = 4, 'b' = 2etc.

Le Seq.sumByprend le compte pour chaque lettre et additionne tous les nombres du 0compte pour cette lettre. Donc, si 'a' = 4la collection serait ce 0, 1, 2, 3, 4qui est résumé est 10. Puis Seq.sumByadditionne tous ces totaux.


2
Vous pouvez réduire votre score de 2 en changeant let qsur let j, car le qest déjà utilisé dans les deux cas Seq.
Kevin Cruijssen le

2

APL (Dyalog) , note 15

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

Essayez-le en ligne!

 obtenir la saisie de texte

∘.=⍨ table d'égalité avec soi

+\ somme cumulée sur

1 1⍉ diagonale (lit. réduit les deux dimensions en une dimension)

+/ somme


2

Retina , score 68 45 43

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

Essayez-le en ligne! Le lien montre le score. Edit: Merci à @MartinEnder qui a enregistré 20 octets en utilisant des correspondances superposées au lieu d’indicatifs et trois octets supplémentaires en regroupant les étapes de sorte que le sdrapeau ne doit être appliqué qu’une seule fois. A enregistré deux autres octets en calculant le nombre triangulaire différemment, en évitant le besoin d'un tri.



2

Score Perl 5 91 83

Utilise le -pdrapeau qui ajoute 2 à cause du p en split.

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

Bienvenue chez PPCG!
Laikoni

1
En utilisant votre réponse comme base et en appliquant certaines techniques de la page de conseils, j'ai réussi à réduire votre score à 31: Essayez-le en ligne! . $` is automatically print ed after each call so we can use that to store the score and /./ g` renvoie une liste de tous les caractères $_, ce qui est moins cher que split//.
Dom Hastings

Je sais que c’est un vieux défi, mais vous pouvez encore réduire le score: essayez-le en ligne!
Xcali

2

Octave , 39 bytes, Score 69

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

Essayez-le en ligne!

Bien qu'il y ait une autre réponse Octave, celle-ci est entièrement la mienne et constitue une approche différente. En plus, elle marque moins :).

L’approche se résume à la première recherche du nombre (b) de chaque caractère unique, obtenu à l’aide de la fonction histogramme. Ensuite, pour chaque élément, nous calculons la somme de 1 à b qui est effectuée à l'aide de la formule(b*(b+1))/2 . Ensuite, les sommes individuelles sont toutes additionnées dans le score final.

Lors des tests, il semble que les consoles coûtent très cher car beaucoup d’entre elles sont nécessaires. J'ai optimisé le score initial d'environ 88 en réorganisant les questions afin de minimiser le nombre de crochets ouverts / fermés - nous passons donc maintenant à la valeur / 2 sur le total final plutôt qu'individuellement, et j'ai également modifié la formule pour (b^2+b)/2car cela nécessite moins de crochets.


1
Malheureusement, cela semble échouer sur la chaîne vide:error: hist: subscript indices must be either positive integers less than 2^31 or logicals
Laikoni

2

Common Lisp, score 286 232 222

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

Score élevé en raison de la syntaxe verbeuse des opérateurs intégrés de Common Lisp.

Essayez-le en ligne!

Le code non-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

2

Mathematica, score 54

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

contribution

["abcdefg"]

grâce à hftf


Total[#(#+1)/2&@Counts@Characters@#]&scores 54.
hftf
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.