Calculate the binary split sum of a word

22

3

Take a string, s containing printable ASCII-characters as input, and output its "binary split sum". Need an explanation?

How do you get the binary split sum?

We'll use the string A4 as an example in the following explanation.

  • Convert the characters to binary, treating each letters as a 7-bit ASCII character

    A -> ASCII 65 -> 1000001
    4 -> ASCII 52 -> 0110100
    
  • Concatenate the binary numbers into a new binary number

    A4 -> 1000001 & 0110100 -> 10000010110100
    
  • Split the new binary number into chunks, where no 1 can have a 0 to its left. You should not split consecutive 1s.

    10000010110100 -> 100000, 10, 110, 100
    
  • Convert these binary numbers to decimal

    100000, 10, 110, 100 -> 32, 2, 6, 4
    
  • Take the sum of these numbers:

    32 + 2 + 6 + 4 = 44
    

So, the output for the string A4 should be 44.


Test cases:

a
49

A4
44

codegolf
570

Hello, World!
795

Stewie Griffin

Posted 2017-05-14T20:28:19.747

Reputation: 43 471

2I think this would have been a nicer challenge without the ASCII conversion step, just taking the (decimal) number after step 2 as input. – xnor – 2017-05-14T20:37:34.670

Well, 8372 actually. – xnor – 2017-05-14T20:40:30.697

1@xnor, you might be right, and it would be cleaner. I had fun solving this in Octave though, and I hope others will enjoy solving it too :) – Stewie Griffin – 2017-05-14T20:42:02.873

Answers

12

Python 2, 86 81 76 bytes

-5 bytes thanks Adnan
-5 bytes thanks xnor

s=0
for c in input():s=s*128+ord(c)
print eval(bin(s).replace('01','0+0b1'))

Try it online!

for c in input():s=s*128+ord(c) to do the ASCII conversion numerically, where *128 is used to left shift s 7 times (steps 1 and 2)
eval(('0'+new_bin).replace('01','0+0b1')) to split and sum (steps 3, 4 and 5)

Rod

Posted 2017-05-14T20:28:19.747

Reputation: 17 588

Nice trick with the eval! Doing the ASCII conversion numerically saves some bytes.

– xnor – 2017-05-14T21:17:40.263

7

Jelly, 13 bytes

Oḅ128BŒg;2/ḄS

Try it online!

How it works

Oḅ128BŒg;2/ḄS  Main link. Argument: s (string)

O              Ordinal; map characters to their code points.
 ḅ128          Unbase 128; convert the resulting list from base 128 to integer.
     B         Binary; Convert the resulting integer to base 2.
      Œg       Group consecutive, equal bits.
        ;2/    Concatenate all non-overlapping pairs.
           Ḅ   Unbinary; convert from base 2 to integer.
            S  Take the sum.

Dennis

Posted 2017-05-14T20:28:19.747

Reputation: 196 637

I've missed that trick of base conversion before. – Jonathan Allan – 2017-05-14T21:45:18.423

Ah, nice trick indeed! – Adnan – 2017-05-15T04:30:08.117

6

MATL, 14 bytes

YB!'1+0*'XXZBs

Try it online!

Explanation

Consider input 'A4' as an example.

YB        % Implicit input. Convert to binary using characters '0' and '1'. 
          % Gives a char matrix, where each row corresponds to a number
          % STACK: ['1000001'; '0110100']
!         % Transpose. This is necessary because MATL uses column-major 
          % order when linearizing a matrix into a vector
          % STACK: ['10'; '01'; '01'; '00'; '01'; '00'; '10']
'1+0*'    % Push this string: regexp pattern
          % STACK: ['10'; '01'; '01'; '00'; '01'; '00'; '10'], '1+0*'
XX        % Regexp. Linearizes the first input into a row (in column-major
          % order), and pushes a cell array of substrings that match the
          % pattern given by the second input
          % STACK: {'100000'; '10'; 110'; '100'}
ZB        % Convert each string into a decimal number. Gives numeric vector
          % STACK: [32; 2; 6; 4]
s         % Sum. Implicitly display
          % STACK: 44

Luis Mendo

Posted 2017-05-14T20:28:19.747

Reputation: 87 464

5

05AB1E, 18 bytes

Code:

Çžy+b€¦JTR021:2¡CO

Explanation:

Ç                   # Take the ASCII value of each character
 žy+                # Add 128 to each value (to pad each with enough zeros)
    b               # Convert to binary
     €¦             # Remove the first character
       J            # Join the array
        TR021:      # Replace 01 by 021
              2¡    # Split on the number 2
                C   # Convert from binary to decimal
                 O  # Sum them all up

Uses the 05AB1E encoding. Try it online!

Adnan

Posted 2017-05-14T20:28:19.747

Reputation: 41 965

5

05AB1E, 14 bytes

Çžy+b€¦Jγ2ôJCO

A port of my Jelly answer, using the 128 offset from Adnan's 05ab1e answer (rather than the 256 in the Jelly answer I wrote).

Try it online!

How?

Çžy+b€¦Jγ2ôJCO
Ç              - to ordinals
   +           - add
 žy            - literal 128
    b          - to binary
     €         - for each
      ¦        -   dequeue
       J       - join
        γ      - group into chunks of equal elements
          ô    - split into chunks of
         2     - literal 2
           J   - join
            C  - from binary
             O - sum

Jonathan Allan

Posted 2017-05-14T20:28:19.747

Reputation: 67 804

3

JavaScript (ES6), 97 92 bytes

s=>eval(s.replace(/./g,c=>(128+c.charCodeAt()).toString(2).slice(1)).replace(/1+/g,'+0b$&'))

Edit: Saved 5 bytes with some help from @ConorO'Brien.

Neil

Posted 2017-05-14T20:28:19.747

Reputation: 95 035

My own solution was 97 bytes, too: s=>eval([...s].map(e=>(e.charCodeAt()+128).toString(2).slice(1)).join``.replace(/1+0*/g,'+0b$&')) You can use my replace method to save a byte, I think – Conor O'Brien – 2017-05-14T22:11:14.953

1@ConorO'Brien More than a byte, I think! – Neil – 2017-05-14T23:03:37.107

Oo, n​i​c​e :​D – Conor O'Brien – 2017-05-14T23:07:13.647

3

Japt, 18 12 bytes

c_¤ùT7Ãò< xÍ
c_           // Firstly, take the input and map over it as charcodes.
  ¤          // Take the binary representation of each item
   ùT7       // and left-pad it with zeroes to standardize the items.
      Ã      // After all of the above,
       ò<    // partition the result where ever a 0 precedes a 1.
          xÍ // Then sum the numbers from base 2.

Takes input as a single string.
I also tried out the 128 or 256 addition used by other answers, but 0-padding was shorter to use.

Shaved off a whole whopping 6 bytes thanks to ETHproductions and Oliver.

Try it out here.

Nit

Posted 2017-05-14T20:28:19.747

Reputation: 2 667

You can use more auto-functions here: òÈ<YÃ can be ò< (with trailing space), and Ën2Ãx can be xn2. You can also use T in place of 0 to save on the comma. (Also, feel free to join us in the Japt chatroom if you ever have questions or would like help with golfing :-) )

– ETHproductions – 2018-04-06T15:05:13.203

@ETHproductions Thanks again, especially for the T trick, didn't know you could (ab)use variables for that, that's very handy. The auto-function xn2 looks a bit weird when compiled, x("n", 2), so I think it will still take a bit before I fully understand the logic behind them. With your help, the Japt solution is now tied for the first place with the Jelly answer.

– Nit – 2018-04-06T19:11:59.223

ETHproductions recently made a shortcut for n2 : Í. It hasn't hit TIO yet, but you can use it here: https://ethproductions.github.io/japt/?v=1.4.5&code=Y1+k+VQ3w/I8IHjN&input=IkE0Ig==

– Oliver – 2018-04-06T20:25:01.853

@Oliver Wow, that's very bleeding edge, that isn't even covered in the interpreter shortcuts reference yet. Thanks a lot! – Nit – 2018-04-07T08:03:35.137

2

Jelly, 16 15 bytes

-1 byte thanks to Dennis (no need to flatten by 1 when a full flatten is fine - replace ;/ with F)

O+⁹Bṫ€3FŒg;2/ḄS

Try it online!

How?

O+⁹Bṫ€3FŒg;2/ḄS - Main link: list of characters, s    e.g. "A4"
O               - cast to ordinal (vectorises)        [65,52]
  ⁹             - literal 256
 +              - add (vectorises)                    [321, 308]
   B            - convert to binary (vectorises)      [[1,0,1,0,0,0,0,0,1],[1,0,0,1,1,0,1,0,0]]
    ṫ€3         - tail €ach from index 3              [[1,0,0,0,0,0,1],[0,1,1,0,1,0,0]]
       F        - reduce with concatenation           [1,0,0,0,0,0,1,0,1,1,0,1,0,0]
        Œg      - group runs of equal elements        [[1],[0,0,0,0,0],[1],[0],[1,1],[0],[1],[0,0]]
          ;2/   - pairwise reduce with concatenation  [[1,0,0,0,0,0],[1,0],[1,1,0],[1,0,0]]
             Ḅ  - convert from binary (vectorises)    [32,2,6,4]
              S - sum                                 44

Jonathan Allan

Posted 2017-05-14T20:28:19.747

Reputation: 67 804

1;/ can be replaced with F. – Dennis – 2017-05-14T21:32:08.957

2

PHP, 116 Bytes

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);$t=mb_split("(?<=0)(?=1)",$r);echo array_sum(array_map(bindec,$t));

Online Version

PHP, 117 Bytes

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);$t=preg_split("#0\K(?=1)#",$r);echo array_sum(array_map(bindec,$t));

Try it online!

PHP, 120 Bytes

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);preg_match_all("#1+0+#",$r,$t);foreach($t[0]as$b)$s+=bindec($b);echo$s;

Try it online!

or

for(;$c=ord($argn[$i++]);)$r.=sprintf("%07b",$c);preg_match_all("#1+0+#",$r,$t);echo array_sum(array_map(bindec,$t[0]));

Jörg Hülsermann

Posted 2017-05-14T20:28:19.747

Reputation: 13 026

1

Pyth, 21 bytes

It's too long...

siR2:.BiCMQ128"1+0+"1

Test suite.

Leaky Nun

Posted 2017-05-14T20:28:19.747

Reputation: 45 011

1

[F#], 249 245 bytes

open System
let rec c a=function|[]->[a]|'0'::'1'::y->(a+"0")::(c""('1'::y))|x::y->c(a+string x)y
let x i=c""(String.Join("",(Seq.map(fun c->Convert.ToString(int c,2).PadLeft(7,'0'))i))|>Seq.toList)|>Seq.map(fun c->Convert.ToInt32(c,2))|>Seq.sum

Try it online!

Note: the version on tio.run has "open System" in the header, I've added its count to the code above. I'm not sure what the rules are on imports.

Ungolfed

let rec convert acc = function
    | [] -> [acc]
    | '0'::'1'::xs -> (acc + "0") :: (convert "" ('1'::xs))
    | x::xs -> convert (acc + string x) xs

let calculateSum input =
    let binary = Seq.map (fun x -> Convert.ToString(int x, 2).PadLeft(7, '0')) input

    String.Join("", binary)
    |> Seq.toList
    |> convert ""
    |>Seq.map (fun x -> Convert.ToInt32(x, 2))
    |>Seq.sum

Brunner

Posted 2017-05-14T20:28:19.747

Reputation: 331

if open System is the same as C#s using System; then yes you need to include it in the count. If you can do it in F# you could fully qualify whatever the System is for . For example, in C# System.Console... instead of using System;Console... – TheLethalCoder – 2017-05-15T16:27:00.460

@TheLethalCoder It is the same, yes. Also, thanks for clarifying this :) I opted for the "open.." version because it's not only String, but also Convert that live in that namespace. – Brunner – 2017-05-15T17:17:20.487

0

Perl 6, 62 bytes

{sum map {:2(~$_)},.comb».ord».fmt('%07b').join~~m:g/11*0*/}

Sean

Posted 2017-05-14T20:28:19.747

Reputation: 4 136

use .ords instead of .comb».ord. prefix [~] can often be used instead of .join. comb exists which does the m:g/… thing. /11*0*/ can be shortened to /1+0*/. I came up with {sum map {:2($_)},comb /1+0*/,[~] .ords».fmt('%07b')}

– Brad Gilbert b2gills – 2017-05-14T22:18:14.143

0

mathematica 193 bytes

f=FromDigits;l=Flatten;(S=Split@l@Table[PadLeft[IntegerDigits[ToCharacterCode@#,2][[k]],7],{k,StringLength@#}];Plus@@Table[f[RealDigits@f@Join[S[[i]],S[[i+1]]],2],{i,1,Length@S-1,2}]+Last@l@S)&

J42161217

Posted 2017-05-14T20:28:19.747

Reputation: 15 931

You can save 7 bytes by doing f=FromDigits;l=Flatten; at the start, and then replacing all instances of those two functions with f and l. – numbermaniac – 2017-05-15T07:37:01.363

0

J, 34 bytes

[:+/@(,#.;.1~1,1=2#.\,)(7#2)#:3&u:

Try it online!

Explanation

[:+/@(,#.;.1~1,1=2#.\,)(7#2)#:3&u:  Input: array of characters S
                              3&u:  Get ASCII values of each character
                       (7#2)        Array with 7 copies of the value 2
                            #:      Convert each value to a base 2 array with length 7
[:  (                 )             Operate on those binary values
                     ,                Flatten it
                 2  \                 For each infix of size 2
                  #.                    Convert it to decimal from binary
               1=                     Test each value for equality to 1
             1,                       Prepend a 1
      ,                               The flattened binary values
         ;.1~                         Chop that at each occurrence of a 1
       #.                               Convert each chop from binary to decimal
 +/@                                Reduce by addition

miles

Posted 2017-05-14T20:28:19.747

Reputation: 15 654

0

J, 40 bytes

+/>#.&.>(1,}.|.1 0 E.|.b)<;.1 b=.,#:a.i.

usage:

+/>#.&.>(1,}.|.1 0 E.|.b)<;.1 b=.,#:a.i.'A4'

returns 44

protist

Posted 2017-05-14T20:28:19.747

Reputation: 570

0

Clojure, 150 bytes

#(loop[[c & C](for[i % j[64 32 16 8 4 2 1]](mod(quot(int i)j)2))p 0 r 0 R 0](if c(if(=(dec c)p 0)(recur C c 1(+ R r))(recur C c(+(* 2 r)c)R))(+ R r)))

Well I was hoping the conversion from ASCII to bytes was shorter than this. The actual loop body is quite short, using r to accumulate the current result and R to accumulate the total result. If the previous bit p is 0 and the current bit c is 1 then we split a new chunk and accumulate to R, otherwise we update the r and keep R as it was.

NikoNyrh

Posted 2017-05-14T20:28:19.747

Reputation: 2 361

0

Python 123 bytes

lambda w:sum(map(lambda x:int(x,2),"".join(map(lambda x:bin(ord(x))[2:].zfill(7),list(w))).replace("01","0:1").split(":")))

Updated, thanks to Martin Ender.

ShadowCat

Posted 2017-05-14T20:28:19.747

Reputation: 11

1Welcome to PPCG! All answers need to be either full programs or callable functions (as opposed to snippets where the input is stored in a hardcoded variable). The function can be unnamed, though, so including a lambda w: would be enough to make your answer valid. – Martin Ender – 2018-03-28T21:51:00.853

Sorry, I probably didn't phrase that well. Your edit is still invalid because a) the input is hardcoded, b) If this is a full program, it doesn't actually print the result. For a full program you'd have to read the input from standard input or a command-line argument, and print the result to standard output. That's why I said it's probably easiest if you submit it as a function by adding lambda w:. – Martin Ender – 2018-03-30T10:22:05.877

Ohhh, Ok, i get it, it would be enough like this: f=lambda w:sum(map(lambda x:int(x,2),"".join(map(lambda x:bin(ord(x))[2:].zfill(7),list(w))).replace("01","0:1").split(":"))) – ShadowCat – 2018-04-04T17:15:34.163

yep, that's valid. You don't even need the f=, because we allow unnamed functions (unless you reference the function name for recursive calls). – Martin Ender – 2018-04-04T21:01:21.753

0

K (oK), 31 bytes

Solution:

+/2/'_[;x]&x&~~':x:,/(7#2)\'`i$

Try it online!

Examples:

+/2/'_[;x]&x&~~':x:,/(7#2)\'`i$,"a"
49
+/2/'_[;x]&x&~~':x:,/(7#2)\'`i$"A4"
44
+/2/'_[;x]&x&~~':x:,/(7#2)\'`i$"codegolf"
570
+/2/'_[;x]&x&~~':x:,/(7#2)\'`i$"Hello, World!"
795

Explanation:

Convert to ASCII values, convert to 7-bit binary, flatten, find where differs, and against original list to find where 1s differ. Cut at these indices, convert back to decimal and sum up:

+/2/'_[;x]&x&~~':x:,/(7#2)\'`i$ / the solution
                            `i$ / convert to integer
                     (7#2)      / draw from 2, 7 times => 2 2 2 2 2 2 2
                          \'    / decode each (convert to binary)
                   ,/           / flatten
                 x:             / save as x
             ~~':               / not-not-each previous (differ)
            &                   / and with
           x                    / x
          &                     / indices where true
     _[;x]                      / projection, cut x at ...
  2/'                           / encode each (convert from binary)
+/                              / sum up

Bonus

Managed a 31 byte version in K4 too, but as there's no TIO for it I'm posting my oK solution.

+/2/:'_[;x]@&x&~~':x:,/1_'0b\:'

streetster

Posted 2017-05-14T20:28:19.747

Reputation: 3 635

0

APL (Dyalog), 30 bytes

{+/2⊥¨(1∘+⊆⊢)∊¯7↑¨2⊥⍣¯1¨⎕UCS⍵}

Try it online!

How?

⎕UCS⍵ - Unicodify

2⊥⍣¯1¨ - encode each in binary

¯7↑¨ - and pad to the left with zeros to 7 places

- flatten

1∘+⊆⊢ - partition by self increased by one

2⊥¨ - decode each from binary

+/ - sum

Uriel

Posted 2017-05-14T20:28:19.747

Reputation: 11 708