8
\$\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\$
  • \$\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\$ – Bassdrop Cumberwubwubwub Sep 26 '16 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\$ – Mego Sep 26 '16 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 Sep 26 '16 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\$ – Peter Taylor Sep 26 '16 at 13:39
  • 1
    \$\begingroup\$ Why didn't the MATL submission win? \$\endgroup\$ – Stewie Griffin Nov 15 '16 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\$
  • \$\begingroup\$ @Ajay Isn't this the winner by code-golf criteria? \$\endgroup\$ – Jonathan Allan Oct 3 '16 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
    \$\begingroup\$ Nice idea with the boolfun package, +1! \$\endgroup\$ – Billywob Sep 26 '16 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\$
  • 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 Sep 26 '16 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 Sep 26 '16 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 Sep 26 '16 at 10:48
  • \$\begingroup\$ @manatwork Updated my answer. Thanks for both suggestions! \$\endgroup\$ – seshoumara Sep 26 '16 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\$
  • \$\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\$ – Kevin Cruijssen Sep 26 '16 at 8:46
  • \$\begingroup\$ I need to learn more!...btw Thanks \$\endgroup\$ – Numberknot Sep 26 '16 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\$ – Kevin Cruijssen Sep 26 '16 at 9:22
  • \$\begingroup\$ @KevinCruijssen 😵oops!•••• and thanks../人 ◕ ‿‿ ◕ 人\ \$\endgroup\$ – Numberknot Sep 26 '16 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\$
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\$
  • 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 Sep 26 '16 at 10:01
  • 1
    \$\begingroup\$ @rturnbull Nice, I knew there were some unnecessary stuff in there. \$\endgroup\$ – Billywob Sep 26 '16 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 Sep 26 '16 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\$
  • 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\$ – Bassdrop Cumberwubwubwub Sep 26 '16 at 11:32
  • \$\begingroup\$ @BassdropCumberwubwubwub Thank you. \$\endgroup\$ – Lmis Sep 26 '16 at 12:05
  • \$\begingroup\$ Can match`1`g.length work? \$\endgroup\$ – Titus Sep 26 '16 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\$
  • \$\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 Sep 26 '16 at 12:56
  • \$\begingroup\$ I tried that but there is no .Sum() for string \$\endgroup\$ – hstde Sep 26 '16 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 Sep 26 '16 at 13:03
  • \$\begingroup\$ of course, stupid me forgetting halve the code \$\endgroup\$ – hstde Sep 26 '16 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
    \$\begingroup\$ Nice. You can golf q like so: q=n=>n&&n%2+q(n>>1) \$\endgroup\$ – ETHproductions Sep 26 '16 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\$
  • \$\begingroup\$ ToCharacterCode can be called directly on a string. Total can be shortened to Tr. \$\endgroup\$ – Martin Ender Sep 26 '16 at 13:58

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