30
\$\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\$
  • 2
    \$\begingroup\$ Is it OK if I return an iterator, rather than a list? \$\endgroup\$ – DJMcMayhem Jul 5 '16 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 Jul 5 '16 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 Jul 5 '16 at 20:00

69 Answers 69

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\$
  • \$\begingroup\$ x%2<1 and x%2>0 are shorter \$\endgroup\$ – mbomb007 Jul 5 '16 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 Jul 5 '16 at 19:43
  • \$\begingroup\$ @mbomb007 I'd just flip the condition: []if x%2 else[x] \$\endgroup\$ – Random832 Jul 5 '16 at 19:44
  • \$\begingroup\$ wait a minute, why do you even need a condition after the break \$\endgroup\$ – Random832 Jul 5 '16 at 19:45
  • \$\begingroup\$ And with the condition gone, adding a tuple works and is one character shorter: L+=x, \$\endgroup\$ – Random832 Jul 5 '16 at 19:48
2
\$\begingroup\$

Perl 5 + Perligata, 173 bytes

145 bytes, plus 28 for -MLingua::Romana::Perligata

Use as perl -MLingua::Romana::Perligata foo.pl; input (from stdin) and output (to stdout) are underscore-separated strings of decimal integers. Tested on Strawberry 5.20.2 with version 0.6 of Perligata, released two days ago; I don't know whether it works with Perligata version 0.50.

huic vestibulo perlegementum da.his _ scindementa da.per in his fac sic
si recidementum hoc tum II fac sic I exi cis
hoc tum _ egresso scribe
cis

Obviously this is clear as a bell. In case it's not, run it with -MLingua::Romana::Perligata=converte instead of -MLingua::Romana::Perligata, and perl will, instead of running the script, output a translation into regular Perl:

 $_ = Lingua::Romana::Perligata::getline (*STDIN );
 @_ = split ( '_');
for $_ (@_) {if ( ($_ % 2)) {exit ( 1)}
;
print (STDOUT $_, '_')}

For a token-by-token analysis, use -MLingua::Romana::Perligata=discribe.


Golfing notes:

  • It seems from the documentation that ultimus si recidementum hoc tum II fac. would work instead of si recidementum hoc tum II fac sic ultimus cis, saving 7 bytes. But it doesn't (it gives a "iussa absentia" error).
  • Undocumented (but unsurprising), you don't need a space after ..
  • (Also unsurprising,) scinde doesn't need a second argument, and uses hoc. Alas, exi needs an argument.
  • Instead of huic vestibulo perlegementum da, I tried -pMLingua::Romana::Perligata, but couldn't get it to work.

Just for kicks (although this whole answer was just for kicks):

  • After cleaning it up to Huic vestibulo perlegementum da. His lacunam scindementa da. Per in his fac sic si recidementum hoc tum II fac sic I exi cis. Hoc tum lacunam egresso scribe cis., Google Translate gives This court perlegementum grant. His gap scindementa grant. 2 By that time, do so in the following 1, Go out and do so if recidementum on this side. This was the gap as soon as write on this side..
\$\endgroup\$
  • \$\begingroup\$ what is this witchery \$\endgroup\$ – Addison Crump Jul 8 '16 at 15:57
2
\$\begingroup\$

JavaScript, 27 25 bytes

a=>a.filter(v=>a=a&&~v%2)

The filer expression repeatedly assigns to a and uses the value of a as a filter predicate. a holds either the initial array value (always truthy) or the boolean of whether only even values have been seen. When a turns false (i.e., an odd number appears), then subsequent runs of the a = a && ... logical AND operation short cirucits, and we use false for the rest of the run.

The bitwise NOT ~v turns even numbers to odd and vice versa, so ~v%2 returns a truthy value for even input and falsy values for odd input.

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

SML, 44 bytes

an assignment at my university functional programming course

Yay, functional programming! So as an assignment solution, this would probably look like this:

(* 'a takeWhile : ('a -> bool) -> 'a list -> 'a list *)
fun takeWhile p nil     = nil
  | takeWhile p (x::xr) = if p x then x :: takeWhile p xr else nil

(* takeWhileEven : int list -> int list *) 
val takeWhileEven = takeWhile (fn x => x mod 2 = 0)

which can be golfed to

fun t[]=[]|t($ :: &)=if$mod 2=0then$ ::t&else[]

However using foldr is 3 bytes shorter:

foldr(fn($,r)=>if$mod 2=0then$ ::r else[])[]
\$\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\$

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\$
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\$
  • \$\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 Jul 5 '16 at 20:24
  • \$\begingroup\$ Nevermind. That returns tuples, which wouldn't work as input. \$\endgroup\$ – Dennis Jul 5 '16 at 20:29
  • \$\begingroup\$ Actually, += allows extending lists with tuples for some reason, so E+=L.pop(0), still works. \$\endgroup\$ – Dennis Jul 5 '16 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 Jul 6 '16 at 2:21
  • \$\begingroup\$ @Dennis And *E creates a tuple, so E+=L.pop(0), is extending a tuple, not a list. \$\endgroup\$ – mbomb007 Jul 6 '16 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\$
  • \$\begingroup\$ @cat - GCC complains when I don't have the int c,char**v. How do you get around that? \$\endgroup\$ – owacoder Jul 6 '16 at 20:03
  • \$\begingroup\$ Ehh, never mind, I can't get what I was after. Tips for golfing in C \$\endgroup\$ – cat Jul 6 '16 at 20:26
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\$

Perl 6, 14 bytes

{|$_,1...^*%2}

Try it online!

Finally, a use for a neat trick I found involving .... This is an anonymous code block that basically filters the list until it reaches an element that succeeds in the condition *%2 i.e. odd. Then we return the list excluding the last element. Since an element has to pass the condition at some point, otherwise it attempts to extrapolate off the end of the list, we append a 1 to the input list.

Note this isn't the intended use for the sequence operator ..., which is usually used to create sequences based off several parameters. We're using the behaviour that the end condition is checked against the starting elements as well, and will stop even before any new elements are generated.

Explanation:

{            }  # Anonymous code block
 |$_,1          # Using the input list appended with 1
      ...       # Take up to
          *%2   # The element that is odd
         ^      # And exclude the last element
\$\endgroup\$
  • \$\begingroup\$ :P i think a lot of people know about the trick \$\endgroup\$ – ASCII-only Apr 4 at 23:28
  • \$\begingroup\$ @ASCII-only Really? I haven't seen it before in the wild, if you could point me to any solutions that use ... to filter a list like this, I'd be very interested to see them \$\endgroup\$ – Jo King Apr 4 at 23:31
  • \$\begingroup\$ it's not really filtering though, i thought it's just the conventional use of creating a range until a predicate is satisfied? \$\endgroup\$ – ASCII-only Apr 4 at 23:33
  • \$\begingroup\$ well, the other conventional use \$\endgroup\$ – ASCII-only Apr 4 at 23:35
  • \$\begingroup\$ i mean, i guess the "checked against the starting elements" usually isn't taken advantage of \$\endgroup\$ – ASCII-only Apr 5 at 9:57
0
\$\begingroup\$

Python, 55

t=lambda A,i=0:i<len(A)and~A[i]%2and[A[i]]+t(A,i+1)or[]

The following one is a generator, so it doesn't return a list, 49 bytes:

def t(A):
 for a in A:
  if a%2:break
  else:yield a

# usage: list(t([2, 3, 4]))
\$\endgroup\$
  • \$\begingroup\$ "The output should be a list" \$\endgroup\$ – mbomb007 Jul 5 '16 at 19:49
  • \$\begingroup\$ @mbomb007: thanks for reformating, looks better now \$\endgroup\$ – shooqie Jul 5 '16 at 19:51
0
\$\begingroup\$

Perl, 29 + 1 (for -p) = 30 bytes

s/(\d+)/($1)[$o or$o=$1%2]/eg

Use like perl -p myfile.pl, where myfile.pl contains the above code, or just perl -pn 's/(\d+)/($1)[$o or$o=$1%2]/eg'. Takes input from standard input.

\$\endgroup\$
  • \$\begingroup\$ s/-pn/-pe/. Also, I haven't tested, but I imagine you can omit the parens from the first argument to s and use $& instead of $1. \$\endgroup\$ – msh210 Jul 7 '16 at 22:40
0
\$\begingroup\$

JavaScript, 29 bytes

a=>a.filter(e=>!(s|=e%2),s=0)

or

a=>a.filter(e=>s&=!(e%2),s=1)

How it works (1st version)

1) Take input array a and return the result of calling filter on it. This will keep every element for which the function we pass into filter returns a truthy value.

2) Abuse the second parameter to filter (normally used to set the this value to the function, but we don't use this in the program) to initialize s to 0.

3) For the filter function, set s to s | (e % 2), which will evaluate s to 0 iff s was 0 before and the element e is even. So, s will be 0 up until the first odd value, after which it will never be 0 again. Then simply return the negation of s, keeping the first run of even values (!0 === true) and discarding the rest.

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

Julia, 24 bytes

!x=1∈x%2?!x[1:end-1]:x

Try it online!

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

TSQL 67 bytes

DECLARE @ table(i INT identity, n INT)
INSERT @ values(14),(42),(2324),(97090),(4080622),(1),(171480372)

SELECT n FROM(SELECT n,sum(n%2)over(order by i)z FROM @)x WHERE z=0

Fiddle

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

Factor, 55 bytes

[ dup [ odd? ] find drop over length over swap ? head ]

Using the following substitution regexes, the test cases from the question can be turned into a Factor test suite.

s/\[((?:\d*(?: )?)*)\]\s+->\s+\[((?:\d*(?: )?)*)\]/{ { $2 } } [ { $1 } take-while-even ] unit-test/g
s/,//g

takewhile-even.factor

USING: kernel math sequences ;
IN: takewhile-even

: take-while-even ( seq -- newseq )
  dup [ odd? ] find drop over length over swap ? head ;

takewhile-even-tests.factor

USING: tools.test takewhile-even ;
IN: takewhile-even.tests

{ { 14 42 2324 97090 4080622 171480372 } } [ { 14 42 2324 97090 4080622 171480372 } take-while-even ] unit-test
{ { 42 14 42 2324 } } [ { 42 14 42 2324 } take-while-even ] unit-test
{ {  } } [ { 7 14 42 } take-while-even ] unit-test
{ {  } } [ {  } take-while-even ] unit-test
{ { 171480372 } } [ { 171480372 13 14 42 } take-while-even ] unit-test
{ { 42 14 42 } } [ { 42 14 42 43 41 4080622 171480372 } take-while-even ] unit-test

Run them with "takewhile-even" test.

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

Perl 5.10, 36 bytes

Different way of doing it when compared to the other Perl answers which are based on regexes. 35 bytes + 1 byte for -a flag.

for(@F){$_%2?last:push@a,$_}say"@a"

Try it here!

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

Java, 98 bytes

int[]f(int[]t){int i=0;for(;i<t.length&&t[i]%2<1;i++);return java.util.Arrays.copyOfRange(t,0,i);}

Ideone it!

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

PHP, 57 55 bytes

function f($i){foreach($i as $n){if($n&1)die;echo $n;}}

Ungolfed:

function f($i){
    foreach($i as $n){
        if($n & 1) die;
        echo $n;
    }
}

The function takes an array $i as an input parameter.

$n & 1 will return 1 if $n is odd and 0 is $n is even.

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

Python 3, 72 bytes

It's a bit of a boring answer, but itertools has a function for this...

from itertools import*
lambda x:[i for i in takewhile(lambda y:y%2+1,x)]

An anonymous function that takes input of the list x via argument and returns a list.

Try it on Ideone

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

><>, 70 bytes

Takes input as any number of decimal integers separated by a single character (anything but a digit), and prints out the list newline-separated.

v;oan;?<
0!2&::&\%
&>i:0(?^'0'-::0($9)+?v&a*+&!
>^   oan&0~&;?%2&::&~<

Try it online!

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

Javascript (using external library - Enumerable) (42 bytes)

n=>_.From(n).TakeWhile(y=>y%2<1).ToArray()

Code explanation: Library built in implementation...

enter image description here

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

Tcl, 44 bytes

proc T L {lmap e $L {if $e%2 {break}
set e}}

Try it online!

Tcl, 64 bytes

proc T L {set M {}
lmap e $L {if $e%2 break
lappend M $e}
set M}

Try it online!

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

Funky, 44 bytes

t=>{z={}fori=0;(!t[i]&1)*i<#t;i++z[i]=t[i]z}

Try it online!

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

GNU sed, 20 bytes

s/[^ ]*[13579]\b.*//    

Try it online!

Input and output are space-separated numbers.

Alternate solution, 22 bytes (20 + -n)

s/[24680]$/&/p;t;q;:

Try it online! Uses newlines instead of spaces this time.

\$\endgroup\$

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.