102
\$\begingroup\$

Write a function or program that determines the cost of a given string, where

  • the cost of each character equals the number of how many times the character has occurred up to this point in the string, and
  • the cost of the string is the sum of its characters' costs.

Example

For an input of abaacab, the cost is computed as follows:

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

Thus the cost for the string abaacab is 14.

Rules

  • The score of your submission is the cost of your code as defined above, that is your submission run on its own source code, with a lower score being better.
  • Your submission should work on strings containing printable ASCII-characters, plus all characters used in your submission.
  • Characters are case-sensitive, that is a and A are different characters.

Testcases

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

Leaderboard

var QUESTION_ID=127261,OVERRIDE_USER=56433;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px} /* font fix */ body {font-family: Arial,"Helvetica Neue",Helvetica,sans-serif;} /* #language-list x-pos fix */ #answer-list {margin-right: 200px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Score</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

\$\endgroup\$
12
  • 2
    \$\begingroup\$ How do program flags such as -n for Perl count towards the score? It traditionally counts as 1 byte because the edit distance between the standard perl -e and perl -ne is 1, but for this challenge, will the n count for the purposes of counting duplicates? \$\endgroup\$
    – Value Ink
    Jun 19, 2017 at 20:20
  • 2
    \$\begingroup\$ @ValueInk Yes, I think counting the n is the fairest option. \$\endgroup\$
    – Laikoni
    Jun 19, 2017 at 20:34
  • 1
    \$\begingroup\$ I really wish there was a brainfuck solution to this challenge. \$\endgroup\$
    – Peter1807
    Jun 21, 2017 at 12:16
  • 10
    \$\begingroup\$ +1 for The score of your submission is the cost of your code \$\endgroup\$
    – luizfzs
    Jun 22, 2017 at 15:21
  • 1
    \$\begingroup\$ cost of a character is defined as how often this character has already occurred in the string, i'd probably changing to how many times the character has occurred up to this point to make it clearer that the first use costs 1, not 0 \$\endgroup\$ Jan 19, 2018 at 19:33

92 Answers 92

2
\$\begingroup\$

brainfuck, score 897

,[<<[[->+>-<<]>>[<]<[<]<[<]<[+<<]>>>>[>]>[->+>+<<]>[-<+>]<<<]<+[->>+<<]>>>[->+<]>[>]>,]<<[<]<

Try it online!

Ends on the cell with the correct value. Assumes a cell size larger than the score of the string, otherwise it'll wrap (got a little suspicious when the interpreter said the score was 188).

\$\endgroup\$
4
  • \$\begingroup\$ You might be able to change this to use one of the many binary-encoded brainfuck dialects that exist to lower your score... \$\endgroup\$ Jan 19, 2018 at 5:22
  • \$\begingroup\$ CompressedFuck looks promising. \$\endgroup\$ Jan 19, 2018 at 5:26
  • 2
    \$\begingroup\$ @EsolangingFruit That's like saying switching to Jelly may save some bytes on your Java answer... :P \$\endgroup\$ Jan 19, 2018 at 22:45
  • 2
    \$\begingroup\$ @ConorO'Brien I'd argue that it's more akin to switching from a version of Jelly which must begin with the header module Main where: import Jelly.Types; import Jelly.Builtins. The problem being solved is the same, it's just more competitive. But I do see your point - switching languages is essentially switching competitions, so it's not really fair to ask someone to do that. \$\endgroup\$ Jan 20, 2018 at 0:17
2
\$\begingroup\$

Husk, Score 9

½§+L(Σ´×=

Try it online!

Explanation:

This calculates the score as sum_i (n_i^2 + n_i)/2, where i is indexed arbitrarily across unique character types and n_i is the number of characters of type i in the input. But since sum_i n_i is the length of the input, this reduces to (1/2) * (L + sum_i n_i^2)

Code breakdown:

o ½ (§ + L (o Σ (´ (× =)))        --With parentheses and two implicit compositions
                   (× =)          --1 or 0 for each equality check between elements of its first and second arguments
                (´ (× =))         --argdup, 1 or 0 for each equality check between elements of its only argument
           (o Σ (´ (× =))         --# of equalities between pairs (this will give sum_i n_i^2)
         L                        --length
    (§ + L (o Σ (´ (× =)))        --length + sum_i n_i^2
o ½ (§ + L (o Σ (´ (× =)))        --1/2 * (length + sum_i n_i^2)
\$\endgroup\$
1
  • \$\begingroup\$ You can do Ṡṁ# instead of (Σ´×= for a score of 7. \$\endgroup\$
    – Zgarb
    Mar 17, 2018 at 11:37
2
\$\begingroup\$

Rust, 265 255 bytes. Score: 1459 1161

fn main(){let mut z=String::new();std::io::stdin().read_line(&mut z);let Z=z.trim_right_matches(|x|x=='\r'||x=='\n');let mut q:Vec<u8>=Z.bytes().collect();q.sort();let(mut k,mut W,mut j)=(0,0u8,0);for Y in&q{if*Y==W{j+=1}else{j=1;W=*Y}k+=j}print!("{}",k)}

Ungolfed

fn main() {
    let mut input_string = String::new();
    std::io::stdin().read_line(&mut input_string);
    let trimmed = input_string
        .trim_right_matches(|c| c == '\r' || c == '\n');
    let mut chars: Vec<u8> = trimmed.bytes().collect();
    chars.sort();
    let (mut total_score, mut last_char, mut last_score) = (0, 0u8, 0);
    for letter in &chars {
        if *letter == last_char {
            last_score += 1;
        } else {
            last_score = 1;
            last_char = *letter;
        }
        total_score += last_score;
    }
    print!("{}", total_score);
}

Edit: improved answer by renaming variables and altering code

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Welcome to PPCG! In this challenge the score of your submission is the cost of your code, which I think is 1459. \$\endgroup\$
    – Laikoni
    Mar 15, 2018 at 13:26
  • \$\begingroup\$ Edited. Thanks for pointing that out \$\endgroup\$ Mar 15, 2018 at 13:32
  • 2
    \$\begingroup\$ This also means you can improve your score quite a bit by choosing characters as variable names which are not already contained in other keywords. \$\endgroup\$
    – Laikoni
    Mar 15, 2018 at 13:34
  • 2
    \$\begingroup\$ You're still using a lot of variable names that are characters used elsewhere. jkqvxz and most capitals are unused and would improve the score. \$\endgroup\$ Mar 16, 2018 at 10:19
2
\$\begingroup\$

Python 2. Score:142 115

def     f(a):
        x=0
        for y in set(a):z=a.count(y);x+=.5*z*-~z
        print x

EDIT:-27 thanks to @Kevin Cruijssen

\$\endgroup\$
3
  • \$\begingroup\$ By changing the indentations and the space between def f(a) to tabs you lower your score to 126. In addition, you can change (z+1) to -~z to lower it more to 117. And you can remove the 0 in 0.5 to lower it to 115. Try it online. \$\endgroup\$ Mar 21, 2018 at 15:00
  • \$\begingroup\$ @KevinCruijssen Thanks, Changed! \$\endgroup\$
    – sonrad10
    Mar 21, 2018 at 15:11
  • 1
    \$\begingroup\$ Try it online! link \$\endgroup\$ Mar 21, 2018 at 17:51
2
\$\begingroup\$

Japt -x, 9 7 points

å+ ®èZÌ

Try it

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Not that hard to optimise for score when you can solve it using entirely unique characters, huh :P \$\endgroup\$ Jan 22, 2018 at 15:45
2
\$\begingroup\$

SNOBOL4 (CSNOBOL4), score: 681

	s	=iNPUT
	Y	_table()
d	S	LEN(1) . x REM . S	:F(b)
	Y<X>	=y<X> + 1	:(D)
b	Z	_convert(Y,'aRrAy')
N	j	=J + 1
	G	_z[j,2]	:f(q)
	o	=o + g * G + g	:(N)
q	OUtpuT	_O / 2
end

Try it online!

looks a bit scary, but SNOBOL matches identifiers case-insensitively, which dropped the score by around 100 points. Note that it requires a single line of input, so I've replaced \n with ; in the input field (which is still valid SNOBOL).

The SNOBOL4 implementation on TIO allows for an additional 16 point golf, as = and _ are both allowable as the assignment operator. How neat!

\$\endgroup\$
2
\$\begingroup\$

Mathematica, score 42

Total[#^2+#].5&@*CharacterCounts

input

["abcdefg"]

thanks to hftf
thanks to att

\$\endgroup\$
2
  • \$\begingroup\$ Total[#(#+1)/2&@Counts@Characters@#]& scores 54. \$\endgroup\$
    – hftf
    Sep 19, 2017 at 14:48
  • \$\begingroup\$ 42: Total[#^2+#].5&@*CharacterCounts \$\endgroup\$
    – att
    Feb 20 at 8:28
2
\$\begingroup\$

Husk, 5 bytes, score 5

ΣṁŀgO

Try it online!

Different and (so far) shorter strategy to Natte's or Sophia Lechner's Husk answers.

    O   # sort the input
   g    # and group equal adjacent values;
 ṁ      # now, for each group
  ŀ     # make a range 1..length of the group
 ṁ      # and flatten all the ranges into one list;
Σ       # then output the sum
\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog), score 27 18 11 10

Reduced score by 7 thanks to @Adám by using a tradfn and using 1⊥ to sum the frequencies

Reduced score by 1 thanks to @rabbitgrowth by using a function instead

1⊥{+/⍳≢⍵}⌸

Try it online!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Same method, score 11: 1⊥{+/⍳≢⍵}⌸⍞ \$\endgroup\$
    – Adám
    Jun 19, 2017 at 17:55
  • \$\begingroup\$ @Adám Thanks, the 1⊥ trick is really neat \$\endgroup\$
    – user41805
    Jun 20, 2017 at 8:36
  • \$\begingroup\$ Can't the be omitted? It turns into a function, and it still works. \$\endgroup\$ Feb 20 at 13:32
  • \$\begingroup\$ @rabbitgrowth Thanks! \$\endgroup\$
    – user41805
    Feb 21 at 14:43
1
\$\begingroup\$

Python 2, score 83

lambda z:sum((2*z.count(x)+1)**2/8for x in set(z))

Try it online

1/8 (1 + 2 n)^2 -1/8 is the same as n (n+1) / 2. Floor division removes the need to subtract 1/8.

\$\endgroup\$
0
1
\$\begingroup\$

Clojure, score 96

#(apply +(for[[k j](frequencies %)](*(inc j)j 0.5)))

Five spaces and pairs of brackets...

\$\endgroup\$
1
\$\begingroup\$

Actually, score 12

;╗╔⌠╜cRΣ⌡MΣ

Try it online!

Explanation:

;╗╔⌠╜cRΣ⌡MΣ  (implicit input: S)
;╗           save a copy of S in register 0
  ╔          uniquify S (call it A)
   ⌠╜cRΣ⌡M   for each unique character in A:
    ╜c         count the number of occurrences in S
      R        range(1, count+1)
       Σ       sum
          Σ  sum

Repeating the Σ is two points less than using an alternative formulation with no repeated characters (i`+Y).

\$\endgroup\$
1
\$\begingroup\$

J, score 23

$-:@+[:+/,/@(=/~)

Try it online!

\$\endgroup\$
1
\$\begingroup\$

F#, score:12641110

-154 points, thanks to @Laikoni

let x(y:bool)=System.Convert.ToInt32(y)
let rec p(k:string)q=
 let j=k.Length
 if(j=1)then(x(k.[0]=q))else p k.[0..(j-2)] q+x(k.[j-1]=q)
let rec d(a:string)=
 let z=a.Length
 if(z<2)then z else d a.[0..(z-2)]+p a (a.[z-1])

You need to call the d function. In a more readable form:

let x (y:bool)=
    System.Convert.ToInt32(y)
let rec e (c:string) b=
    let j=c.Length
    if(j=1)then
        (x(c.[0]=b))
    else 
        e c.[0..(j-2)] b+x (c.[j-1]=b)
let rec d (a:string)=
    let h=a.Length
    if(h<2)then 
        h 
    else
        d a.[0..(h-2)]+e a (a.[h-1])

Explanation

It is a recursive algorithm, the base case is, if the length of the string is less than 2 (0 or 1), the score will be the length of the string. This is because, if the length is 0 (empty string), we have no characters, so the score is 0, and if the length is 1, that means, that the string consists of only 1 character, so the score is 1.

Otherwise it trims the last character of the string, and to the score of the truncated string adds the count of the last character in the untruncated string.

The counting algorithm is also recursive. Its base case is, when the length of the string is one, then the count is 1, if the string matches with the character, and 0 otherwise. This can also be done, if we convert the bool to an int, and this results in a lower score.

Otherwise it trims the last character of the string, calculates the count of that string, and if the last character matches the character, we are calculating the count of, adds one to the count. This is again, better, if we convert that boolean to an int.

\$\endgroup\$
1
  • \$\begingroup\$ I think you can remove some white space, e.g. around the parentheses in let rec e (c:string) b=. Also using some character as variable which does not appear in keywords will improve your score, e.g. y instead of e. \$\endgroup\$
    – Laikoni
    Jun 20, 2017 at 14:44
1
\$\begingroup\$

Octave , score 77 31 bytes

*same as @LuisMendo 's MATL answer.

@(a)nnz(triu(a==a'))

Try it online!

Previous answer:

@(d,g=accumarray(+d',1)-(0:254))sum(g(g>0));

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ You could probably save a point by ditching the semicolon. Couldn't test it as it doesn't seem to work with TIO. \$\endgroup\$ Jun 21, 2017 at 22:05
  • \$\begingroup\$ @TomCarpenter Without ; doesn't work. however such a lambda cab be used in arrayfun. \$\endgroup\$
    – rahnema1
    Jun 22, 2017 at 2:55
1
\$\begingroup\$

AWK, 39 bytes, Score 54

BEGIN{RS="(.)"}{M+=++s[RT]}END{print M}

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Changing S to some unused character reduces the score by two. \$\endgroup\$
    – Laikoni
    Jun 21, 2017 at 21:45
1
\$\begingroup\$

FIREBIRD, score 3577

Version to calculte the score:

SELECT COALESCE(SUM(C),0)FROM(WITH RECURSIVE T AS(SELECT 1 AS I,SUBSTRING(CAST(:V AS BLOB)FROM 1 FOR 1)AS S FROM RDB$DATABASE UNION ALL SELECT I+1,SUBSTRING(CAST(:V AS BLOB)FROM I+1 FOR 1)FROM T WHERE I < CHAR_LENGTH(CAST(:V AS BLOB)))SELECT T.*,(SELECT COUNT(T2.I) FROM T T2 WHERE T2.S=T.S AND T2.I<=T.I)AS C FROM T WHERE CAST(:V AS BLOB) <> '')

Below is the idented version of the code, in case anyone want to now. I'm sorry for any mistakes, first time here actually posting!

SELECT COALESCE(SUM(C), 0)
FROM (
  WITH RECURSIVE T AS (
    SELECT 1 AS I, SUBSTRING(CAST(:V AS BLOB) FROM 1 FOR 1) AS S
    FROM RDB$DATABASE

    UNION ALL

    SELECT I+1, SUBSTRING(CAST(:V AS BLOB) FROM I+1 FOR 1)
    FROM T
    WHERE I < CHAR_LENGTH(CAST(:V AS BLOB))
  )
  SELECT T.*, (SELECT COUNT(T2.I) FROM T T2 WHERE T2.S = T.S AND T2.I <= T.I) AS C
  FROM T
  WHERE CAST(:V AS BLOB) <> ''
)

Explanation

I start my select in a system table SELECT 1 AS I, SUBSTRING(CAST(:V AS BLOB) FROM 1 FOR 1) AS S FROM RDB$DATABASE, which always has only one row. Using that only one row, I return 1 as a column I, and the character that exists in the input in the I value.

Let's say I've passed 'abaacab' as input:

╔═══╦═══╗
║ I ║ S ║
╠═══╬═══╣
║ 1 ║ a ║
╚═══╩═══╝

In the UNION ALL part, I start to increment the index from the first select, until it reaches the end of the input. So, in the example I would get this:

╔═══╦═══╗
║ I ║ S ║
╠═══╬═══╣
║ 1 ║ a ║
║ 2 ║ b ║
║ 3 ║ a ║
║ 4 ║ a ║
║ 5 ║ c ║
║ 6 ║ a ║
║ 7 ║ b ║
╚═══╩═══╝

After that, I also select the count of ocurrences from the value on S, that has already appeared in indexes below the I. So, in a column C I now have the 'cost' of that character, which I only need to SUM after to get the value.

╔═══╦═══╦═══╗
║ I ║ S ║ C ║
╠═══╬═══╬═══╣
║ 1 ║ a ║ 1 ║
║ 2 ║ b ║ 1 ║
║ 3 ║ a ║ 2 ║
║ 4 ║ a ║ 3 ║
║ 5 ║ c ║ 1 ║
║ 6 ║ a ║ 4 ║
║ 7 ║ b ║ 2 ║
╚═══╩═══╩═══╝

I used BLOB as the type from the input, to not get limited by size.

\$\endgroup\$
4
  • \$\begingroup\$ Welcome to PPCG! \$\endgroup\$
    – Laikoni
    Jun 22, 2017 at 21:33
  • \$\begingroup\$ @Laikoni Thanks! I forgot to add a short explanation, my bad. I will do it later, in case anyone is interested. \$\endgroup\$ Jun 22, 2017 at 22:17
  • \$\begingroup\$ I'm always interested in explanations. :) Have you checked for each space wether it can be removed or not? Some of them look unnecessary, e.g. (SUM(C), 0) or AS (SELECT, thought I don't know firebird. \$\endgroup\$
    – Laikoni
    Jun 23, 2017 at 6:03
  • \$\begingroup\$ Thanks @Laikoni, with your advice I saved some points. I've just add my explanation. If its too bad just let me know so I can try to make a better one. \$\endgroup\$ Jun 23, 2017 at 11:17
1
\$\begingroup\$

K/Kona, score 19

+/,/1+!:'(#:)'=

Works as:

              = (implicitly take arg as input), group -> make dictionary of characters to their occurring indices
         (#:)'= count each of these 
    1+!:'(#:)'= get a list from 0->n-1 for each of these counts, add one to each 
+/,/1+!:'(#:)'= finally, reduce to single list, sum reduce this list

Example:

k)+/,/1+!:'(#:)'="+/,/1+!:'(#:)'="
19
k)+/,/1+!:'(#:)'="abaacab"
14

Legible q equivalent:

(sum/)raze 1+til count each group 
\$\endgroup\$
0
1
\$\begingroup\$

Pyke, score 7

cemSss

Try it here!

c      -    count_occurrences(input)
 e     -   values(^)
  mS   -  [range(1,i+1) for i in ^]
    ss - sum(sum(i)for i in ^)
\$\endgroup\$
1
\$\begingroup\$

Jelly, 10 9 bytes; Score 10 9

ṢŒrzẆṪRẎS

Try it online!

This is the first time I use Jelly, and I didn't want to check other people's answers because I wanted to try it myself. I probably reinvented the wheel a couple times there. Suggestions and feedback are greatly appreciated.

EDIT: -1 byte for removing ɠ and taking the input as an argument.

Explanation:

ṢŒrzẆṪRẎS           #Main Link; input abaacab
Ṣ                   #sorts input; aaaabbc
 Œr                 #run-length encode, or the number of times a character appears; a4b2c1
   z                #zip; ['abc', [4, 2, 1]]
    Ẇ               #takes every contiguous sublists
     Ṫ              #Pops the last element; [4, 2, 1]
      R             #Takes the range of every element; [[1,2,3,4],[1,2],1]
       Ẏ            #Collapses every element into a single array; [1,2,3,4,1,2,1]
        S           #Sum and implicitly print; 14.

(no idea why, but the code doesn't work without , although it gives the exact same output as z)

\$\endgroup\$
1
1
\$\begingroup\$

J, score 14

1#.2!1+#/.~

Try it online!

Outgolfed by the other J solution, but figured I'd post this anyways since it uses a slightly different method.

\$\endgroup\$
1
\$\begingroup\$

Japt, score 12 (+2 for -x) = 14

¬n ó¥ ËÊõÃc

Explanation

¬n ó¥ ËÊõÃc                                             "abaacab"
¬            // Split the input into an array of chars  ["a","b","a","a","c","a","b"]
 n           // Sort                                    ["a","a","a","a","b","b","c"]
   ó¥        // Partition matching items                [["a","a","a","a"],["b","b"],["c"]]
      Ë      // map; For each array:
       Ê     //   Get the length x                      [4,2,1]
        õ    //   Create a range [1...x]                [[1,2,3,4],[1,2],[1]]
         Ã   // }
          c  // Flatten                                 [1,2,3,4,1,2,1]
-x           // Sum                                     14

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Attache, score 36

Sum@Map&:(Count#Last)@Prefixes

Try it online!

Explanation

Sum@Map&:(Count#Last)@Prefixes

This is a composition of 3 functions:

  • Prefixes - this simply obtains the prefixes of the input
  • Map&:(Count#Last) - This is a mapped fork. This is equivalent to arr.map { e -> e.count(e.last) } So, for each character, this counts the occurrences of that character so far.
  • Sum - this sums all of these numbers.
\$\endgroup\$
1
\$\begingroup\$

MS-SQL, score 308

I'm using a completely different technique from my other answer, with additional restrictions, so I'm submitting them separately:

SelEcT SUm(k)FROM(SELECT k=couNt(*)*(CoUNT(*)+1)/2froM spt_values,z WHERE type='P'AND number<len(q)GROUP BY sUBstring(q,number+1,1))L

Caveats: this must be run from the master database of a MS-SQL server set to a case-sensitive collation (mine is set to SQL_Latin1_General_CP850_BIN2).

Input is via varchar field q in pre-existing table z, per our IO rules. Formatted:

SelEcT SUm(k)
FROM
    (SELECT k=couNt(*)*(CoUNT(*)+1)/2
     froM spt_values,z 
     WHERE type='P'
     AND number<len(q)
     GROUP BY sUBstring(q,number+1,1)
    )L

The trick here is to use a "number table" to join with the input table, which allows me to separate each character into its own row, then group by matching characters, count them up, calculate the score of each, and sum them all together. All the rest is minimizing score by playing with character case, since SQL keywords are not case sensitive.

MS-SQL has a system table in the master database called spt_values with a lot of junk in it, but I restrict it to type='P', I get a nice number table with 0 through 2047.

\$\endgroup\$
1
\$\begingroup\$

K4, score 15

Solution:

+/,/{1+!#x}'=

Example:

q)k)+/,/{1+!#x}'="Programming Puzzles & Code Golf"
47

Explanation:

+/,/{1+!#x}'= / the solution
            = / group
    {     }'  / apply lambda to each (')
         x    / implicit lambda input
        #     / count length
       !      / range 0..n
     1+       / add one
  ,/          / flatten list
+/            / sum up

Notes:

In Q this could be written as:

q)sum raze { 1 + til count x } each group "Programming Puzzles & Code Golf"
47
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 112 95 points

Came up with the original version down the pub on Friday before noticing the scoring mechanism. Golfed a few points off before ditching it in favour of more beer, but it seemed a shame to let it go to waste completely!

s=>s.map((w,x)=>s.map((y,z)=>y!=w|z<x?8:++n),n=0)|n
  • 7 points saved thanks to ETHProductions

Try it

o.innerText=(f=
s=>s.map((w,x)=>s.map((y,z)=>y!=w|z<x?8:++n),n=0)|n
)([...i.value=""+f]);oninput=_=>o.innerText=f([...i.value])
<input id=i type=number><pre id=o>


Original, 112 points

o.innerText=(f=
a=>a.reduce((x,y,z)=>x+a.filter(v=>v==y&--w<0,w=z).length,0)
)([...i.value=""+f]);oninput=_=>o.innerText=f([...i.value])
<input id=i type=number><pre id=o>

\$\endgroup\$
0
1
\$\begingroup\$

Python 3, score 89 85

lambda	y:sum(y[:x+1].count(v)for	x,v in enumerate(y))

Try it online!

\$\endgroup\$
0
1
+500
\$\begingroup\$

Standard ML, 66 bytes, score 113

fun$(a::z)=1+length(List.filter(fn y=>y=a)z)+	$z|
$_=0;$o explode;

This code defines an anonymous function which is bound to the implicit result identifier it. Try it online!

Explanation

The ungolfed code looks like this:

fun f (a::z) = 1 + length (List.filter (fn y => y=a) z) + f z
  | f  _     = 0
val g = f o explode

The function g takes a string as input, converts it to a list of characters with explode, and passes it on to the function f which recurses over the list, with a being the current character and z being the remaining list. For each a the number of occurrences of a in z is computed by filtering z to contain only chars equivalent to a and taking the length of the resulting list. The result is incremented by one to account for the current occurrence of a and added to result of the recursive call of f on z.

\$\endgroup\$
1
\$\begingroup\$

PHP, 44 bytes, score 78:

While($C=ORD($argn[$p++]))$s-=++$$C;EcHo-$s;

Almost Jörg´s solution, but one byte shorter.


PHP, 51 bytes, score 80

ForEach(COUNT_CHARS($argn)As$p)$z-=~$p*$p/2;echo$z;

Run as pipe with -nR or try them online

\$\endgroup\$
1
\$\begingroup\$

Perl6/Rakudo, 45 bytes, score 66

Run with perl -ne:

say [+] bag(.comb).values.map({($_+1)*$_/2});

Uses the essential nature of a Bag (like a set with a count per member).

Step by step:

.say;                      # abaacab
say .comb;                 # (a b a a c a b)
say bag(.comb);            # Bag(a(4), b(2), c)
say bag(.comb).values;     # (2 4 1)
say bag(.comb).values.map({($_+1)*$_/2});        # (3 10 1)
say [+] bag(.comb).values.map({($_+1)*$_/2});  #14

Also note that each character's score can be calculated from its occurrences as (n+1)*n/2.

Edited because I cannot evidently read.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ In this challenge, the score of your submission is the cost of your code which I think is 75. \$\endgroup\$
    – Giuseppe
    Mar 15, 2018 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.