9
\$\begingroup\$

The Challenge

Given a non-empty string containing only lowercase or uppercase letters and no spaces:

  • Sum up the ASCII values for each character instance in the input string.

  • The sum will be converted to binary.

  • And, the result will be the number of ones in the binary value.

Input example:

abcDeFAaB
  1. Sum up the ASCII values for each character instance, so for this example: 97+98+99+68+101+70+65+97+66 = 761.

  2. Convert the sum (761) to binary. This will give 1011111001.

  3. The final result will be the number of ones (7).

So the output for this example is 7.

Winning Criterion

This is , so shortest answer in bytes wins!

\$\endgroup\$
6
  • \$\begingroup\$ I'm wondering, what's with all the downvotes? Maybe this challenge isn't too hard but it's not trivial either. Currently it stands for a 0/-3 score. Why? \$\endgroup\$ Commented Sep 26, 2016 at 7:49
  • 10
    \$\begingroup\$ This is just three separate challenges that already exist mashed together: sum of ordinals (the averaging part is a trivial addition), decimal to binary (a subset of the linked challenge), and count ones in binary. \$\endgroup\$
    – user45941
    Commented Sep 26, 2016 at 7:50
  • \$\begingroup\$ A mix of multiple existing challenge subsets, even if trivial, shouldn't be considered a duplicate, because in terms of code-golf the solution can be much shorter compared to the multiple ones combined. Indeed, there are already posted answers here of 5 bytes or less. \$\endgroup\$
    – seshoumara
    Commented Sep 26, 2016 at 13:09
  • 4
    \$\begingroup\$ @seshoumara, it's true that sometimes doing A and B is shorter than doing A and then doing B, but only if A and B have something in common. Summing codepoints and bitcount are so orthogonal that only a language specialised for this challenge would do better than essentially taking separate answers to the previous questions and combining them. \$\endgroup\$ Commented Sep 26, 2016 at 13:39
  • 1
    \$\begingroup\$ Why didn't the MATL submission win? \$\endgroup\$ Commented Nov 15, 2016 at 11:07

20 Answers 20

9
\$\begingroup\$

Jelly, 4 bytes

OSBS

TryItOnline

How?

OSBS - Main link: s     e.g. "abcDeFAaB"
O    - ordinal (vectorises)  [97, 98, 99, 68, 101, 70, 65, 97, 66]
 S   - sum                   761
  B  - binary                [1, 0, 1, 1, 1, 1, 1, 0, 0, 1]
   S - sum                   7
\$\endgroup\$
5
\$\begingroup\$

Python3, 46 40 bytes

lambda s:bin(sum(map(ord,s))).count("1")
\$\endgroup\$
4
\$\begingroup\$

MATL, 3 bytes

sBs

Try it online!

Shortest language for this challenge, I think: sum, Binary, sum.

\$\endgroup\$
1
  • \$\begingroup\$ @Ajay Isn't this the winner by code-golf criteria? \$\endgroup\$ Commented Oct 3, 2016 at 6:24
4
\$\begingroup\$

R, 65 53 43 42 bytes

Counting the number of 1s in a binary representation is calculating the Hamming weight of a number, a common procedure in cryptanalysis. There's an R package boolfun, described in this journal article, which handily has a function weight which computes the Hamming weight of any (base 10) integer. That makes our job a lot easier! The rest of the code just sums over the integer representation of STDIN, before sending that to weight.

boolfun::weight(sum(utf8ToInt(scan(,'')))

As an added bonus, this code works for UTF-8 as well as ASCII. There are 7 ones in the binary representation of the sum of 高尔夫 (that's golf in Mandarin).

A note for those playing along at home: unfortunately, boolfun is no longer hosted on CRAN, so if you don't already have it installed you'll have to do it manually with install.packages("https://cran.r-project.org/src/contrib/Archive/boolfun/boolfun_0.2.8.tar.gz", repos = NULL, type = "source"), rather than install.packages(boolfun).

If you really don't want to use boolfun, you can achieve the same result with only two more bytes:

sum(intToBits(sum(utf8ToInt(scan(,''))))==1)
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice idea with the boolfun package, +1! \$\endgroup\$
    – Billywob
    Commented Sep 26, 2016 at 11:36
3
\$\begingroup\$

05AB1E, 6 5 bytes

ÇObSO

Explanation

 Ç      # convert to list of ascii values
  O     # sum
   b    # convert to binary
    SO  # sum as a list

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Bash + coreutils, 43 49 bytes

Edit: corrected version based on manatwork's comments.

od -vAn -tuC|tr '\n ' +|dc -e?2op|grep -o 1|wc -l

Explanation:

The result is printed on STDOUT, with some warnings given on STDERR which can be ignored.

od -vAn -tuC       # get the ASCII value for each string character
|tr '\n ' +        # replace each whitespace with a plus (in dc, a warning will be 
                   #raised for each consecutive plus)
|dc -e?2op         # execute input, calculating the sum, then convert to binary
|grep -o 1|wc -l   # count how many ones exist

Run:

echo -n "abcDeFAaB" | ./script.sh 2> /dev/null

Output:

7

A similar solution is presented below (51 bytes), that had the potential to be shorter, but with xxd I can't concatenate multiple flags and also dc only understands upper case hex letters.

xxd -c1 -u -p|tr \\n +|dc -e16i?2op|grep -o 1|wc -l
\$\endgroup\$
4
  • 1
    \$\begingroup\$ I'm afraid this works only for the first 16 characters of the input string, because od wraps the output. :( Otherwise nice trick to just add the character address to the characters codes. \$\endgroup\$
    – manatwork
    Commented Sep 26, 2016 at 9:41
  • 1
    \$\begingroup\$ @manatwork Good catch, I can fix it with od -An -tuC|tr '[\n ]' +. However, I found a weird printing behavior if input is repetitive. With 32 'a's as input, od prints the first 16 values and then a '*' on the second line :( Do you know how to make it print absolutely each value? I think I have to use xxd instead. \$\endgroup\$
    – seshoumara
    Commented Sep 26, 2016 at 10:38
  • \$\begingroup\$ Wow. Never noticed that weird behavior. But -v seems to get rid of it. BTW, no need for brackets in tr's parameter. \$\endgroup\$
    – manatwork
    Commented Sep 26, 2016 at 10:48
  • \$\begingroup\$ @manatwork Updated my answer. Thanks for both suggestions! \$\endgroup\$
    – seshoumara
    Commented Sep 26, 2016 at 12:51
2
\$\begingroup\$

Java 7,80,76 bytes

Thanks to kevin for saving 4 bytes

int f(char[]a){int s=0,c=0;for(char i:a)s+=i;for(;s>0;s&=s-1,c++);return c;} 

Ungolfed

int f(char[]a){
    int s=0,c=0;
    for(char i:a)
        s+=i;
    for(;s>0;s&=s-1,c++);
        return c;
} 
\$\endgroup\$
4
  • \$\begingroup\$ Dang, you beat me to it. I was just about to post this exact answer.. Btw, you can shorten it a bit to this: int f(char[]a){int s=0,c=0;for(char i:a)s+=i;for(;s>0;s&=s-1,c++);return c;} (76 bytes) \$\endgroup\$ Commented Sep 26, 2016 at 8:46
  • \$\begingroup\$ I need to learn more!...btw Thanks \$\endgroup\$
    – Numberknot
    Commented Sep 26, 2016 at 8:59
  • \$\begingroup\$ Umm, I think you've incorrectly copied/golfed it from your IDE, since you now have the return inside the for-loop instead of behind it (you probably forgot the ; after the for-loop). As you can see in my comment above it first does a for-loop for(;s>0;s&=s-1,c++); ending with semi-colon, and then it returns. And as for the learning part, I've been corrected a lot of times in the past as well. You'll learn it over time. I still have a lot to learn myself and my answers are still occasionally being golfed by others. \$\endgroup\$ Commented Sep 26, 2016 at 9:22
  • \$\begingroup\$ @KevinCruijssen 😵oops!•••• and thanks../人 ◕ ‿‿ ◕ 人\ \$\endgroup\$
    – Numberknot
    Commented Sep 26, 2016 at 9:54
2
\$\begingroup\$

PHP, 79 76 bytes

foreach(str_split($argv[1])as$c)$s+=ord($c);echo substr_count(decbin($s),1);

Test online

Ungolfed testing code:

$argv[1] = 'abcDeFAaB';

foreach(str_split($argv[1]) as $c){
    $s += ord($c);
}
echo substr_count(decbin($s),1);

Test online

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

R, 98 bytes

Was interested in how difficult this would be in R. Turns out you have to do a lot of conversions back and forth (in this solution at least) but I'm sure there should be a shortcut, especially if using packages (can't access any here at work).

sum(as.integer(rev(intToBits(sum(strtoi(sapply(strsplit(readline(),"")[[1]],charToRaw),16L)))))^2)

Could add an explanation if someone is interested.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Before I saw your answer I came up with a very similar solution, which you can see here. You have some unnecessary function calls which can be excluded (e.g. rev, which is needless as you just sum over everything anyway, and the call to sapply is not needed as charToRaw can handle strings with multiple characters). Nice that we ended up with the same solution though! \$\endgroup\$
    – rturnbull
    Commented Sep 26, 2016 at 10:01
  • 1
    \$\begingroup\$ @rturnbull Nice, I knew there were some unnecessary stuff in there. \$\endgroup\$
    – Billywob
    Commented Sep 26, 2016 at 10:09
  • \$\begingroup\$ One more thing: the L after the 16 ensures that it is of type integer and not numeric, which is good practice for careful programming, but for code golf purposes you can (almost?) always omit it, saving a byte. \$\endgroup\$
    – rturnbull
    Commented Sep 26, 2016 at 11:00
1
\$\begingroup\$

><>, 34 bytes

01\
(?\i:@+$0
?!\:2%:}-2,r+$:
n;\~

Try it online!

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

Haskell, 47 bytes

g 0=0;g n=mod n 2+g(div n 2)
g.sum.map fromEnum
\$\endgroup\$
1
\$\begingroup\$

Perl, 36 bytes

Includes +1 for -p

Run with input string without newline on STDIN:

echo -n abcDeFAaB | strsum.pl; echo

strsum.pl:

#!/usr/bin/perl -p
$_=unpack"%b*",pack N,unpack"%32W*"

If the sum of the ASCII values fits in a 16-bit integer you can leave out the 32 and gain 2 more bytes.

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

Julia, 56 Bytes

f(s)=length(filter(i->i=='1',bin(sum(map(Int,[s...])))))

Convert to ascii value, sum up, filter for 1s, take length of result

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

Common Lisp, 53

(lambda(s)(logcount(reduce'+(map'list'char-code s))))
\$\endgroup\$
1
\$\begingroup\$

JavaScript ES6, 80 78 71 Bytes

g=
    s=>[...s].map(c=>r+=c.charCodeAt(),r=0)|r.toString(2).split`1`.length-1
;

console.log(g.toString().length);    // 71
console.log(g('abcDeFAaB'))          // 7

Saved 7 Bytes thanks to @BassdropCumberwubwubwub

Breakdown

 [...s]                              // Split string into array of chars
 .map(c=>r+=c.charCodeAt(),r=0)      // Sum up ASCII values
 |
 r.toString(2)                       // Convert to binary (represented as string)  
 .split`1`.length-1                  // Count occurences of 1
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You can change [...r.toString(2)].map(c=>r+=+c,r=0)|r to r.toString(2).split`1`.length-1 to save 7 bytes \$\endgroup\$ Commented Sep 26, 2016 at 11:32
  • \$\begingroup\$ @BassdropCumberwubwubwub Thank you. \$\endgroup\$
    – Lmis
    Commented Sep 26, 2016 at 12:05
  • \$\begingroup\$ Can match`1`g.length work? \$\endgroup\$
    – Titus
    Commented Sep 26, 2016 at 12:53
1
\$\begingroup\$

PHP, 73 bytes

<?=substr_count(decbin(array_sum(array_map(ord,str_split($_GET[s])))),1);

save to file, call in browser with <scriptpath>?s=<string>

or

<?=substr_count(decbin(array_sum(array_map(ord,str_split($argv[1])))),1);

save to file, run with php <scriptpath> <string>


To run without a file, replace <?= with echo<space> in the second version
and run with php -r '<code>' <string>.

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

C#, 51 50 bytes

s=>Convert.ToString(s.Sum(x=>x),2).Count(x=>x>48);

can be used like this:

Func<string, int> f=s=>Convert.ToString(s.Sum(x=>x),2).Count(x=>x>48);
f("abcDeFAaB") // == 7

would be so much shorter if Int32.ToString() had a to binary flag.

Edit: saved one byte by converting '0' to int

\$\endgroup\$
4
  • \$\begingroup\$ As far as I remember, x=>x inside Sum() is not required, although I'm not sure if it'll do the implicit cast to integers... \$\endgroup\$
    – Yytsi
    Commented Sep 26, 2016 at 12:56
  • \$\begingroup\$ I tried that but there is no .Sum() for string \$\endgroup\$
    – hstde
    Commented Sep 26, 2016 at 12:57
  • 1
    \$\begingroup\$ That's what I feared. How about changing the '0' literal to 48? You actually have it in your example, but not at the golfed code. \$\endgroup\$
    – Yytsi
    Commented Sep 26, 2016 at 13:03
  • \$\begingroup\$ of course, stupid me forgetting halve the code \$\endgroup\$
    – hstde
    Commented Sep 26, 2016 at 13:59
1
\$\begingroup\$

Javascript (ES6), 72 70 bytes

Saved 2 bytes thanks to ETHproductions:

f=
  (s,p=([c,...d])=>c?c.charCodeAt()+p(d):0,q=n=>n&&n%2+q(n>>1))=>q(p(s))
;
console.log(f('abcDeFAaB'));

Explanation:

(s,                                        //Input string
    p=([c,...d])=>c?c.charCodeAt()+p(d):0, //Recursive method to sum up the ASCII values
    q=n=>n&&n%2+q(n>>1)                    //Recursive method to count 1s in the binary form
)=>q(p(s))                                 

Previous solution (72 bytes):

(s,p=([c,...d])=>c?c.charCodeAt()+p(d):0,q=n=>n&&(n&1)+q(n>>1))=>q(p(s))
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Nice. You can golf q like so: q=n=>n&&n%2+q(n>>1) \$\endgroup\$ Commented Sep 26, 2016 at 14:33
0
\$\begingroup\$

Pyth, 8 bytes

ssM.BsCM

Try it online!

Explanation:

      CM  (M)ap ordinals(C) over input
     s    (s)um
   .B     Binary string
 sM       map cast to integer
s         sum
\$\endgroup\$
0
\$\begingroup\$

Mathematica, 53 37 bytes

not the best solution but hey...built-in's ftw

Shortened. Thanks to Martin Ender

DigitCount[Tr@ToCharacterCode@#,2,1]&
\$\endgroup\$
1
  • \$\begingroup\$ ToCharacterCode can be called directly on a string. Total can be shortened to Tr. \$\endgroup\$ Commented Sep 26, 2016 at 13:58

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