17
\$\begingroup\$

Given a list of 2 or more strictly positive integers, sum the first and last half of the list, with the middle element being counted only in the right half if the list has an odd number of elements

Some examples of the middle element being counted in the right half:

[1, 2, 3, 4]       -> Left: [1, 2];    Right: [3, 4]
[1, 2, 3]          -> Left: [1];       Right: [2, 3]
[1, 2, 3, 4, 5]    -> Left: [1, 2];    Right: [3, 4, 5]
[1, 2, 3, 4, 5, 6] -> Left: [1, 2, 3]; Right: [4, 5, 6]

Test Cases

Input

[1, 9]
[9, 5, 5, 7]
[6, 7, 5, 1, 3, 9, 7, 1, 6]
[2, 8, 10, 9, 9, 3, 7, 8, 9, 8, 6, 1, 2, 9, 8, 3, 8, 9, 5]
[2, 3, 1, 8, 6, 2, 10, 6, 7, 6]

Output

[1, 9]
[14, 12]
[19, 26]
[65, 59]
[20, 31]

Reference Program With Two Output Methods

Rules

  • Input/Output can be Taken/Given in any convenient and reasonable format.
  • Functions and full programs are both acceptable.
\$\endgroup\$
  • \$\begingroup\$ So just to confirm, we're permitted to return the two sums in reverse order (right sum then left sum)? \$\endgroup\$ – math junkie May 2 at 18:17
  • \$\begingroup\$ Yes you are allowed to. \$\endgroup\$ – Lyxal May 2 at 18:44
  • \$\begingroup\$ Can the output be in reverse order? \$\endgroup\$ – Shaggy May 2 at 19:28
  • 1
    \$\begingroup\$ @Shaggy The question is asked and answered above \$\endgroup\$ – math junkie May 2 at 19:59

33 Answers 33

1
2
1
\$\begingroup\$

JavaScript (V8), 68 bytes

(l,h=k=>k.reduce((a,e)=>a+e,0))=>([h(l.splice(0,l.length>>1)),h(l)])

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Factor, 55 54 bytes

: f ( s -- s s ) dup length 2/ floor cut [ sum ] bi@ ;

Try it online!

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

asm2bf, 157 bytes

A rather long submission. Let's take a look at the golfed code first:

@l
in r1
cner1,0
cadr2,1
cpsr1
cjn%l
movr3,r2
modr3,2
divr2,2
movr4,r2
addr2,r3
@x
popr1
addr5,r1
decr2
jnzr2,%x
@y
popr1
addr6,r1
decr4
jnzr4,%y
outr6
outr5

Try it online!

I/O format

The program takes input in form of so-called ASCII characters, and produces the output analogically. It's recommended to test the program on a 16-bit brainfuck interpreter (so that the addition doesn't overflow quickly).

asm2bf is a separate language to brainfuck, therefore the Brainfuck restrictions theoretically don't apply to it (because for instance, asm2bf specification says that registers for programmer's convience are at least 16 bits long), but as there is no asm2bf interpreter on TIO, I have to somehow cope with these limitations.

That being said, let's look at some I/O examples:

!"#$% => [33, 34, 35, 36, 37] => [33 + 34, 35 + 36 + 37] => [67, 108] => Cl
!"#$ => [33, 34, 35, 36] => [33 + 34, 35 + 36] = [67, 71] => CG

Explanation

Let's take a look at the ungolfed representation of the code.

Golfing 101

@inloop
    in r1
    cne r1, 0
    cadd r2, 1
    cpush r1
    cjn %inloop

    mov r3, r2
    mod r3, 2
    div r2, 2
    mov r4, r2
    add r2, r3

@right
    pop r1
    add r5, r1
    dec r2
    jnz r2, %right

@left
    pop r1
    add r6, r1
    dec r4
    jnz r4, %left

    out r6
    out r5

Let's answer two questions first:

=> Why does the code compile without spaces between operand and the operation?

The answer is quite simple: the assembler is a very primitive tool. It assumes instruction length of three, therefore after reading instruction name, all spaces are then consumed (but obviously there can be no spaces inbetween).

=> Why is there a space between in and r1?

in is a special instruction, because it has two character length. Under the hood, it's padded to three characters using the floor character (_). Therefore, if the space was ommited, then the assembler would interpret r as the instruction name.

=> Instructions changed. cpo took place of cpush, cad of cadd. Why?

It is perfectly legal, because if every instruction has to have a three byte name, then there must be some alias that magically swaps long instruction names into short instruction names, right?

That's the full list of aliases, as of v1.3.9 (taken from the lib-bfm.lua file):

; Don't ask questions, this is beyond explaining
?band=x00
?bor=x01
?bxor=x02
?bneg=x03
?cflip=x04
; Some common defines
?push=psh
?xchg=swp
; Conditional instructions
?cadd=cad
?csub=csu
?cmul=cmu
?cdiv=cdi
?cmod=cmd
?casl=csl
?casr=csr
?cpow=cpw
?cpush=cps
?cpsh=cps
?cpop=cpo
?cxchg=csw
?cswp=csw
?csrv=crv
?cmov=cmo
?crcl=crc
?csto=cst
?cout=cou

That being said, let's dive into the algorithm.

Algorithm

Let's dissect the code step by step for better understanding:

@inloop
    in r1
    cne r1, 0
    cadd r2, 1
    cpush r1
    cjn %inloop

Some parts are obvious (label declarations for example), some are less. A new feature introduced around v1.3.5 named conditional instructions helps us greatly to solve this task.

The conditional pipeline of this fragment follows:

; if r1 is not zero, set the flag, otherwise clear it
    cne r1, 0
; if flag is set, add 1 to r2 (we accumulate the list length)
    cadd r2, 1
; push the number on the stack if the flag is set.
    cpush r1
; jump to @inloop if the flag is set.
    cjn %inloop

As you can see, it's quite simple to notice, that this tiny block of code will is responsible for:

  • reading the list
  • accumulating it's elements on the stack
  • keeping track of the amount of elements read (in r2)
  • looping until hit EOF

Note: Yes, it's true that you have to set the stack before accessing it, otherwise stack overflow error occurs. In this case, I simply don't make memory accesses, so it's not required to set the stack (because it has nowhere to overflow to)

Between these two loops, there is a tiny block of setup code:

; r3 = r2
    mov r3, r2
; r3 = r2 mod 2
    mod r3, 2
; r2 = r2 / 2
    div r2, 2
; r4 = r2
    mov r4, r2
; r2 = r2 + r3
    add r2, r3

This means, the register values are now:

r4 = r2 / 2
r3 = r2 mod 2
r2 = (r2 / 2) + r3

r3 is used as a flag to indicate whenever the middle element is present and it has to be merged to the list on the right (if count mod 2 is 1, then the count is odd, therefore we have a middle element obviously). The flag is added to the r2 register so the following loop will slurp it from the stack.

Next, there are two very simillar loops. Let's dissect these:

@right
    pop r1
    add r5, r1
    dec r2
    jnz r2, %right

@left
    pop r1
    add r6, r1
    dec r4
    jnz r4, %left

@right will execute until r2 is not zero (id est, the amount of elements left to extract from the stack to make the right list). Everytime an element is popped, the pointer (r2) decreases and the popped value is added to r5.

This being said, @right will simply extract r2 elements from the stack and sum them up to r5.

@left works pretty much the same (it will build the list on the left) returning the result in r6.

And finally, we output both values (sum for the left and the right):

    out r6
    out r5

Appendix A

Generated brainfuck code (around 1.9 kilobyte):

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

Appendix B

The code possibly can be golfed down using constpp - the tool used to set macros on certain [A-Za-z]+ strings and alias them into other, preferably longer strings. Syntax: ?find=replace

There is a tiny chance that one could golf the code down using Lua preprocessor. If you'd like to start a multiline Lua block, use ${...) syntax; single line Lua statements can be prepended with #.

Example on both methods: lib-bfm.lua.

lib-bfm is a file included everytime an assembly program is built using bfmake tool (the one to assemble your code into a ready-to-use Brainfuck program). It's overall recommended to take advantage of it, because it contains some predefined macros (like a memory allocator or quite basic code-preprocessing capabilities).

PS: If anything is unclear, please let me know down in the comments. I'll try to clarify it when I'll have some time on my hands.

| improve this answer | |
\$\endgroup\$
1
2

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.