37
\$\begingroup\$

Introduction and Credit

Today without a fancy prelude: Please implement takewhile.

A variation of this (on a non-trivial data structure) was an assignment at my university functional programming course. This assignment is now closed and has been discussed in class and I have my professor's permission to post it here (I asked explicitly).

Specification

Input

The input will be a list (or your language's equivalent concept) of positive integers.

Output

The output should be a list (or your language's equivalent concept) of positive integers.

What to do?

Your task is to implement takewhile (language built-ins are allowed) with the predicate that the number under consideration is even (to focus on takewhile).

So you iterate over the list from start to end and while the condition (is even) holds, you copy to the output-list and as soon as you hit an element that doesn't make the condition true, you abort the operation and output (a step-by-step example is below). This higher-order functionality is also called takeWhile (takewhile).

Potential corner cases

The order of the output list compared to the input list may not be changed, e.g. [14,42,2] may not become [42,14].

The empty list is a valid in- and output.

Who wins?

This is code-golf so the shortest answer in bytes wins!

Standard rules apply of course.

Test Vectors

[14, 42, 2324, 97090, 4080622, 171480372] -> [14, 42, 2324, 97090, 4080622, 171480372]
[42, 14, 42, 2324] -> [42, 14, 42, 2324]
[7,14,42] -> []
[] -> []
[171480372, 13, 14, 42] -> [171480372]
[42, 14, 42, 43, 41, 4080622, 171480372] -> [42, 14, 42]

Step-by-Step Example

Example Input: [42, 14, 42, 43, 41, 4080622, 171480372]

Consider first element: 42
42 is even (21*2)
Put 42 into output list, output list is now [42]

Consider second element: 14
14 is even (7*2)
Put 14 into output list, output list is now [42,14]

Consider third element: 42
42 is even (21*2)
Put 42 into output list, output list is now [42,14,42]

Consider fourth element: 43
43 is not even (2*21+1)
Drop 43 and return the current output list

return [42,14,42]
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Is it OK if I return an iterator, rather than a list? \$\endgroup\$
    – DJMcMayhem
    Commented Jul 5, 2016 at 19:45
  • 2
    \$\begingroup\$ @DrGreenEggsandIronMan I'm guessing your function has to be able to take its output as its input, guaranteeing they are in the same format. \$\endgroup\$
    – mbomb007
    Commented Jul 5, 2016 at 19:47
  • \$\begingroup\$ @DrGreenEggsandIronMan, I don't think that returning a sublist should be exploited here in the output format. (It's still up to you if you exploit this in your code though). Mbomb's criterion looks most appropriate and compatible with the current challenge so it will be "your output should be a valid input at the very least". \$\endgroup\$
    – SEJPM
    Commented Jul 5, 2016 at 20:00

94 Answers 94

2
\$\begingroup\$

Pyke, 8 bytes

0+2L%fhO

Interpreter fixed, use other links

Uses Dennis' method except my split_at function includes the change - probably a bug

Or with bugfix, 7 bytes

2L%1R@<

Try it here!

2L%     -   map(%2, input)
   1R@  -  ^.index(1)
      < - input[:^]

Or after 2nd bugfix, 6 bytes

2L%fhO

Try it here!

Explanation:

2L%    -   map(%2, input)
   f   -  split_at(input, ^)
    hO - ^[0][:-1]
\$\endgroup\$
2
\$\begingroup\$

JavaScript, 40 bytes

a=>[...a,1].slice(0,a.findIndex(n=>n%2))

How it works

1) Take input array a and add a 1 to the end

2) Find the index of the first odd integer in the array

3) Return a subset of the array from index 0 (inclusive) to the odd integer's index (exclusive)

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

GolfScript, 11 bytes

This is a full GolfScript program that reads a stringified GolfScript array literal (e.g. [28 14 7 0]) and prints out the same array with the first odd element and everything after it removed:

~1\{~&.},p;

Try it online. (Also: Extended version with test harness.)

De-golfed version with comments:

~     # evaluate input
1\    # push the number 1 onto the stack and move it under then input array
{     # start of loop body
  ~   #  bitwise negate the input number (making odd numbers even and vice versa)
  &   #  take bitwise AND of input and the saved number (0 or 1) on stack 
  .   #  duplicate result; filter loop will pop off the duplicate
},    # run loop above over input array, select elements for which it returns true
p     # stringify and print filtered array
;     # pop the number 0/1 off the stack

This solution is based on the GolfScript { }, filter operator, which runs the contents of the code block on each element of an array, and selects the elements of the array for which the code in the block returns a true (i.e. non-zero) value on top of the stack.

Thus, for example, {1&}, would select all odd numbers in an array, and {~1&}, would select all even numbers. The challenge, then, is to make a filter that selects even numbers until it finds the first odd one, and thereafter selects no numbers at all.

The solution I used is to replace the constant bit-mask 1 (used to extract the lowest bit of each input number) with a variable on the stack that stores the result (0 or 1) of the previous filter loop iteration (and is initialized to 1 before the loop). Thus, as soon as the filter returns 0 once, the bitmask also gets set to 0, preventing the filter from ever returning 1 again.

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

Forth, 114 bytes

Forth doesn't really have lists. The parameters must be pushed onto the stack in reverse order, as is typical in Forth. The result will be left on the stack in the same order. This doesn't work on Ideone for some reason, but it works on repl. The new line is required to remove ambiguity of some sort?

: D DEPTH ;
: f D IF 1 D 1 DO D 1- ROLL LOOP D 0 DO I PICK 2 MOD IF D I LEAVE THEN LOOP
DO I ROLL DROP LOOP THEN ;

Try it online

Ungolfed, with comments:

: f DEPTH IF                                ( if stack not empty )
        1 DEPTH 1 DO DEPTH 1- ROLL LOOP     ( put 1 on bottom of stack )
        DEPTH 0 DO                          ( loop over entire stack )
            I PICK 2 MOD IF                 ( if stack[i] is odd )
                DEPTH I LEAVE               ( put range and exit loop )
            THEN
        LOOP
        DO I ROLL                           ( roll eyes )
            DROP
        LOOP                                ( iterate that range and remove )
    THEN
;

This program (my previous attempt) prints the results until it hits an odd number. Everything remaining (not taken) will be left on the stack.

: f DEPTH IF BEGIN DUP 2 MOD DUP 1- IF SWAP . THEN UNTIL THEN ;

Fails if only even integers

\$\endgroup\$
3
  • 5
    \$\begingroup\$ After finishing this, I realized my breakfast was cold. :( \$\endgroup\$
    – mbomb007
    Commented Jul 6, 2016 at 14:54
  • \$\begingroup\$ Too often I find my dinner cold after golfing code at the table. Perhaps Factor will let you be more productive and golfier at the same time? :D \$\endgroup\$
    – cat
    Commented Jul 6, 2016 at 20:03
  • \$\begingroup\$ @c I do my code development for PPCG with online IDEs. But I use Forth because I already know it, it's just difficult to manage a stack in my head. I originally learned Forth because a Minecraft mod added redstone computers that ran a version of Forth entitled MineOS. \$\endgroup\$
    – mbomb007
    Commented Jul 6, 2016 at 20:13
2
\$\begingroup\$

Befunge, 35 Bytes

This code handles numbers between 0 and 65535

1&:v
v-1_@#:@#<
>\:&:2%|
 \+1p4\< ^

Input format :

number_of_values    values(separated by a space)

Here is a version that displays the values at the end of the process :

1&:v>::   v                >00g1+:4g.v
v-1_^#:>#<>$$\$1-:10p000p0-| -g01p00:<
>\:&:2%|                   @
 \+1p4\< ^

You may test the code here, but you will have to add a trailing line with trailing spaces, as this interpret specifies :

« The code torus is only as large as the initial program. Insert more lines or trailing space if data will be put beyond the end of code.»

I don't know if this is acceptable, as I didn't count this trailing in the byte count
nb: it seems that because I'm storing number in the code, the interpreter won't let this program run twice in the correct way. You'll have to reload it.


How does this work: how The interpreter follows the arrows and skip an instruction when crossing '#'

Grey dots are test, and the red line removes unneeded variables from the stack

Using the here in the above interpreter, the saved values are displayed in the code using their representations (I don't know the format). Yes, Befunge is a quite reflective language

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

32-bit x86 machine code, 14 bytes

In hex:

31C9FCADD1E87203E0F941F7D9C3

The list of integers in machine code is something like C's "int a[]". Since the list contains positive integers let's assume the list is zero-terminated, i.e. the value zero marks the end of the array. It's also makes no sense to copy values to another buffer inside this function, that's what strncpy() is for.

The pointer to an array is passed via ESI register. Returns the number of elements comprising the resulting list in ECX.

Disassembly:

31 c9     xor    ecx,ecx  ;ECX=0
fc        cld
_loop:
ad        lodsd           ;Fetch a number to EAX
d1 e8     shr    eax,1    ;EAX=>>1
72 03     jc _end         ;If CF is set then the number is odd, break
e0 f9     loopne _loop    ;--ECX; if(CF==0&&ZF==0)continue
41        inc    ecx      ;Should not include the terminating 0 into the count
_end:
f7 d9     neg    ecx      ;Counting from 0 downward, so ECX=-ECX
c3        ret
\$\endgroup\$
2
\$\begingroup\$

Python 3, 59 bytes

def f(l):
 L=[]
 for x in l:
  if x%2:break
  L+=x,
 return L

Can surely probably be golfed more.

Thanks to everyone who commented :D

\$\endgroup\$
7
  • \$\begingroup\$ x%2<1 and x%2>0 are shorter \$\endgroup\$
    – mbomb007
    Commented Jul 5, 2016 at 19:30
  • \$\begingroup\$ just use x%2 - 0 is false. You can flip the condition to use it for the other one too. \$\endgroup\$
    – Random832
    Commented Jul 5, 2016 at 19:43
  • \$\begingroup\$ @mbomb007 I'd just flip the condition: []if x%2 else[x] \$\endgroup\$
    – Random832
    Commented Jul 5, 2016 at 19:44
  • \$\begingroup\$ wait a minute, why do you even need a condition after the break \$\endgroup\$
    – Random832
    Commented Jul 5, 2016 at 19:45
  • \$\begingroup\$ And with the condition gone, adding a tuple works and is one character shorter: L+=x, \$\endgroup\$
    – Random832
    Commented Jul 5, 2016 at 19:48
2
\$\begingroup\$

Vyxal, 7 bytes

⁽₂Ḋ¾wJh

Try it Online!

Explained

⁽₂Ḋ¾wJh
⁽       # 1-element lambda
 ₂      # check if even
  Ḋ     # group if true
   ¾wJ  # add empty list to end
      h # get head of the list
\$\endgroup\$
2
\$\begingroup\$

Factor, 24 bytes

[ [ even? ] take-while ]

Attempt This Online!

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

jq, 20 bytes

.[:map(.%2)[[1]][0]]

Try it online!

Explanation:

   map(.%2)            Maps the array items to their remainders when divided by 2
           [[1]]       Returns an array of indices where those items equal 1 (odds)
                [0]    Returns the first item of that array of indices
.[:                ]   Returns the original array up until that index
\$\endgroup\$
2
\$\begingroup\$

tinylisp 2, 6 bytes

(p ] e

Try it at Replit. Example session:

tl2> (p ] e
(() remaining-args (eval (concat (q (] e)) (quote-each remaining-args))))
tl2> (def take-while-even _)
take-while-even
tl2> (take-while-even (list 2 4 6 7 8))
(2 4 6)

Explanation

Uses (abbreviated aliases for) the library functions take-while and even?:

(p ] e)
(p    )  ; Partially apply
   ]     ; the take-while function
     e   ; to the even? function

Without using the library's take-while function, I found a rather elegant solution using foldr which is 26 bytes:

(p {(\(N A)(?(e N)(c N A)(

That is, partially apply the { (foldr) function to the following argument:

(\(N A)(?(e N)(c N A)()))
(\                      ) ; Lambda function
  (N A)                   ; that takes a number N and a list A:
       (?              )  ;  If
         (e N)            ;  N is even
              (c N A)     ;  cons N to A
                     ()   ;  Else return empty list

So we end up with a function that takes a list and right-folds it on the above function, with a default starting accumulator value of nil (empty list). This starts from the right end of the list, collecting values as long as they are even, but whenever it encounters an odd value it discards all previous values and starts over.

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

Rust, 25 bytes

|x|x.take_while(|x|x%2<1)
\$\endgroup\$
1
\$\begingroup\$

K, 12 bytes

{x@&~|\2!'x}

Explanation

{           } Function definition.
         'x   For each item in the input list...
       2!     Modulo it with 2 (e.g. 1%2, 5%2, 2%2, etc.) to get a list of booleans.
     |\       Fold | over the list to figure out where the odd numbers begin.
    ~         Flip the values it to get the beginning even numbers (until they turn odd).
   &          Get the indices.
 x@           Index the original list.
\$\endgroup\$
1
\$\begingroup\$

Minkolang 0.15, 12 bytes

nd2%,5&xr$N.

Try it here!

Explanation

nd              Take number from input and duplicate
  2%            Modulo 2
    ,           Logical NOT
     5&         Pop top of stack and jump 5 spaces if truthy
       x        Dump top element
        r       Reverse stack
         $N.    Output whole stack as numbers and stop.

Minkolang's codebox is toroidal, so if the instruction pointer does not stop, then it loops around to the beginning again. Trying to take a number after all input has been exhausted pushes -1, which is very conveniently odd.

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

Python, 43 bytes

lambda l:[x for x in l if l.__imul__(~x%2)]

Calling l.__imul__(n) does l*=n. For n=~x%2, it empties the list when x is even and otherwise leaves it unchanged. The list comprehension iterates and collect elements until it hits an odd number, which stops the iteration by emptying the list. Moreover, because it outputs the now-empty list, the if fails and the current odd value is not included.

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

Lua, 67 Bytes

Simply iterate on each elements of the input using a repeat..until loop. The first iteration will use i=0, which isn't the first element of the input as Lua's tables are 1-indexed, resulting in r[0]=nil which won't do anything as r[0] is already nil.

function f(t)r={}i=0repeat r[i]=t[i]i=i+1until t[i]%2<1return r end
\$\endgroup\$
1
\$\begingroup\$

Python 2, 59 57 56 bytes

def f(L,E=[]):
 while L and~L[0]%2:E+=L.pop(0),
 print E

Try it online

If printing rather than returning a list is allowed, 44 bytes:

L=input()
while L and~L[0]%2:print L.pop(0)

And shorter by xnor, 34 bytes, exits with an error on encountering an odd number:

for x in input():
    0>>x%-2;print x
\$\endgroup\$
6
  • \$\begingroup\$ If you replace E=[] with *E, [L.pop(0)] with L.pop(0), and add parens to print, you can get 55 bytes with Python 3.5. \$\endgroup\$
    – Dennis
    Commented Jul 5, 2016 at 20:24
  • \$\begingroup\$ Nevermind. That returns tuples, which wouldn't work as input. \$\endgroup\$
    – Dennis
    Commented Jul 5, 2016 at 20:29
  • \$\begingroup\$ Actually, += allows extending lists with tuples for some reason, so E+=L.pop(0), still works. \$\endgroup\$
    – Dennis
    Commented Jul 5, 2016 at 21:05
  • \$\begingroup\$ With printing output, you can do much shorter with terminating with error: for x in input():0>>x%-2;print x \$\endgroup\$
    – xnor
    Commented Jul 6, 2016 at 2:21
  • \$\begingroup\$ @Dennis And *E creates a tuple, so E+=L.pop(0), is extending a tuple, not a list. \$\endgroup\$
    – mbomb007
    Commented Jul 6, 2016 at 14:02
1
\$\begingroup\$

Perl, 21 bytes

20 bytes code + 1 bytes command line (-p)

s/ ?\d*[13579]\b.*//

Usage example:

echo "20 4 6 5 3 4" | perl -pe "s/ ?\d*[13579]\b.*//"
\$\endgroup\$
1
\$\begingroup\$

C, 73 69 63 60 54 45 42

This requires a NULL-terminated array of strings as input. It modifies the parameter by chopping the list down to only even entries.

f(char**v){for(;*v&&~atoi(*v++)&1;);*v=0;}

If printing is allowed (45 bytes, doesn't modify parameter):

f(char**v){for(;*v&&~atoi(*v)&1;puts(*v++));}

Here is the previous complete program version (63 bytes):

i;main(int c,char**v){for(;(++i<c)-(atoi(v[i])&1);puts(v[i]));}

Takes input as program arguments.

\$\endgroup\$
3
  • \$\begingroup\$ @cat - GCC complains when I don't have the int c,char**v. How do you get around that? \$\endgroup\$
    – owacoder
    Commented Jul 6, 2016 at 20:03
  • \$\begingroup\$ Ehh, never mind, I can't get what I was after. Tips for golfing in C \$\endgroup\$
    – cat
    Commented Jul 6, 2016 at 20:26
  • \$\begingroup\$ 36 bytes w/ clang, and fixed the last odd number being included in the list. In any other compiler you'd need to declare f(int**v){...} for +3 bytes (note that v doesn't need to be of type char** because you only need it to be a pointer to pointer to something) \$\endgroup\$
    – c--
    Commented Nov 7, 2022 at 2:10
1
\$\begingroup\$

PowerShell 26 bytes

process{if($_%2){break}$_}

Explanation

process{if($_%2){break}$_}
process{                 } # runs the script block once per item in the passed parameter
        if($_%2){break}    # if odd, break out of process{}
                       $_  # implicit output

Testing (save as evenodd.ps1):

PS> 42,14,42,2324 | .\evenodd.ps1
42
14
42
2324
PS> 7,14,42 | .\evenodd.ps1
PS> 171480372,13,14,42 | .\evenodd.ps1
171480372
\$\endgroup\$
1
\$\begingroup\$

Common Lisp, 44 bytes

 (loop as x in(read)while(evenp x)collect x)

Try it online!

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

Husk, 3 bytes

↑¦2

Try it online!

After my adventures with using drop-while to set a default input value with Husk's type inference system, I jumped at the opportunity to use take-while for something normal.

↑      The largest prefix of
       the input
 ¦     in which each element is divisible by
  2    two.
\$\endgroup\$
1
\$\begingroup\$

Java (JDK), 58 bytes

a->a.stream().mapToInt(i->i).takeWhile(i->i%2<1).toArray()

Try it online!

Takes a List<Integer> and outputs an int[].

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

Ruby, 25 bytes

->a{a.take_while &:even?}

Attempt This Online!

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

J-uby, 18 bytes

:take_while+:even?

Attempt This Online!

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

Prolog (SWI), 59 bytes

[]+[].
[H|_]+[]:-1is H mod 2.
[H|T]+[H|R]:-0is H mod 2,T+R.

Try it online!

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

ARM Thumb-2 machine code, 12 bytes

00000000: 04 c8 52 ea c2 72 04 c1 fa d5 70 47              ..R..r....pG

Assembly:

    .syntax unified
    .arch armv7-a
    .thumb
    .globl takewhile
    .thumb_func
    // input: int *, r0
    // output: int *, r1
    // lists are terminated with a negative number
takewhile:
.Lloop:
    // Load number into r2, increment r0
    ldmia   r0!, {r2}
    //  1. shift the LSB of r0 into the MSB
    //  2. Logical OR
    //  3. Set flags on the result
    // On either a terminator or an odd number, the MSB
    // will be set, which sets the N flag. Additionally,
    // this will terminate the list when stored.
    //    r2 = r2 | (r2 << 31);
    //    NF = r2 & 0x80000000;
    orrs.w  r2, r2, r2, lsl #31
    // Store r2 into r1, increment r1
    stmia   r1!, {r2}
    // Loop if MSB was not set (N flag not set)
    bpl     .Lloop
    // Return
    bx      lr

This function requires and outputs an array of positive int32_ts terminated with any negative int32_t. It follows standard C calling convention:

#include <stdint.h>
#include <stdio.h>
void takewhile(const int32_t *input /* r0 */, int32_t *output /* r1 */);

int main(void)
{
    const int32_t input[5] = { 171480372, 13, 14, 42, -1 };
    int32_t output[5];
    takewhile(input, output);
    for (int i = 0; output[i] >= 0; i++) {
        printf("%d, ", output[i]);
    }
    putchar('\n');
}

This takes advantage of the "numbers are positive" condition, and how ARM lets me set the condition codes for free.

I repeatedly logical OR the lowest bit of the values with the highest bit, and test the result. If the result is negative, one of the following is true:

  1. The end of the list was reached (the upper bit was already set)
  2. The number was odd (the lowest bit was set, which when shifted sets the upper bit).

With the example above, the outputted values will be this:

{ 171480372, /* -2147483635 */ 13 | 0x80000000 } 
\$\endgroup\$
1
\$\begingroup\$

Fig, \$3\log_{256}(96)\approx\$ 2.469 bytes

t@E

Try it online!

Builtin. Can't have a functional language without one.

t@E
t@  # Take while
  E # Even
\$\endgroup\$
1
\$\begingroup\$

Nim, 87 bytes

proc t(a:seq[int]):seq[int]=
  var i=0;while i<a.len and a[i]mod 2==0:inc i
  a[0..i-1]

Attempt This Online!

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

Go, 78 64 bytes

func(s[]int,c func(int)){for _,x:=range s{if x%2>0{break}
c(x)}}

Attempt This Online!

  • -14 bytes by @Steffan

Go, generic with predicate, 96 bytes

func f[T any](s[]T,b func(T)bool)(o[]T){for i:=0;i<len(s)&&b(s[i]);i++{o=append(o,s[i])}
return}

Attempt This Online!

\$\endgroup\$
2
  • \$\begingroup\$ 76 bytes \$\endgroup\$
    – naffetS
    Commented Nov 6, 2022 at 0:28
  • \$\begingroup\$ I think it's allowed to output a list via calling a function, so in that case, 64 \$\endgroup\$
    – naffetS
    Commented Nov 6, 2022 at 0:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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