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

1
\$\begingroup\$

Thunno X, \$ 11 \log_{256}(96) \approx \$ 9.05 bytes

lX{D2%)xsTX

Explanation

lX{D2%)xsTX  # Implicit input
lX           # Store [] in x
  {          # Loop through the input list:
   D         #   Duplicate
    2%)      #   If it's odd, break
       xsT   #   Otherwise, append to x
          X  #   And store the result in x
             # The X flag pushes x at the end
             # Implicit output

Screenshot

Screenshot

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

PARI/GP, 23 bytes

a->i=0;[t|t<-a,!i+=t%2]

Attempt This Online!

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

Ly, 16 bytes

&nr[:2%[;]pu9`o]

Try it online!

Pretty brute force, but it's relatively short too. :)

&nr              - Read in list of numbers, reverse stack
   [           ] - Loop until the stack is empty
    :2%          - Dup next number, compute 1|0 if odd/even
       [;]       - If odd, exit the program
          p      - Delete if/then boolean
           u     - Print the number, since it's even
            9`o  - Push 10 (LF) and print as character
\$\endgroup\$
1
\$\begingroup\$

ReRegex, 24 bytes

,?\d*[13579]\b.*//#input

Try it online!

Takes input as a line of comma deliminated Integers. Matches any odd number, and replaces it and the rest of the line with nothing.

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

Thunno 2, 5 bytes

(ɗS;ṫ

Attempt This Online!

Explanation

(ɗS;ṫ  # Implicit input
(  ;   # while loop
 ɗS    # (condition) at least one odd number in the list
    ṫ  # (body) remove the last item
       # Implicit output
\$\endgroup\$
1
\$\begingroup\$

Nekomata, 5 bytes

Ö∫¬∑T

Attempt This Online!

Ö∫¬∑T
Ö       Modulo 2
 ∫      Cumulative sum
  ¬     Logical NOT
   ∑    Sum
    T   Take; get the prefix with the given length

Nekomata, 5 bytes

pᵖ½al

Attempt This Online!

pᵖ½al
p       Non-deterministically choose a prefix
 ᵖ½     Check that all elements are even
   al   Get the last possible value
\$\endgroup\$
1
\$\begingroup\$

Uiua, 7 bytes

▽\׬◿2.

Try it!

▽\׬◿2.
      .  # duplicate
    ◿2   # modulo two
   ¬     # not
 \×      # scan by multiplication
▽        # keep input elements indicated by mask
\$\endgroup\$
1
\$\begingroup\$

K (ngn/k), 7 bytes

(|\2!)_

Try it online!

  • (...)_ set up a weed-out; drop elements from the (implicit) right argument where the code in (...) returns a positive integer (for each item of the input)
  • |\2! do a max-scan on the input mod'ed by 2
\$\endgroup\$
1
\$\begingroup\$

Julia 0.6, 24 bytes

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

Try it online!

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

Japt -g, 3 2 bytes

ôu

Try it here

\$\endgroup\$
2
  • \$\begingroup\$ Fails if the first is odd and the second is even. Working version is ô%2 \$\endgroup\$ Commented Nov 4, 2023 at 13:19
  • \$\begingroup\$ Or, better yet, @noodleman: just ôu \$\endgroup\$
    – Shaggy
    Commented Nov 6, 2023 at 15:09
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\$
2
  • \$\begingroup\$ "The output should be a list" \$\endgroup\$
    – mbomb007
    Commented Jul 5, 2016 at 19:49
  • \$\begingroup\$ @mbomb007: thanks for reformating, looks better now \$\endgroup\$
    – shooqie
    Commented Jul 5, 2016 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\$
1
  • \$\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
    Commented Jul 7, 2016 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\$

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\$
0
\$\begingroup\$

tinylisp repl, 61 bytes

(load library)(d E(q((L)(i(i L(even?(h L))L)(c(h L)(E(t L)))(

Defines a function E (short for "take while Even"). Try it online!

Ungolfed

(load library)
(def takewhile-even
 (lambda (ls)
  (if
   (if ls (even? (head ls)) ls)
   (cons (head ls) (takewhile-even (tail ls)))
   nil))))

Recurse through the list, using cons to build the result list. If the list is empty or if even? returns false, return empty list.

Note #1: Your functional programming professor would not like this function. It's not tail-recursive, so it will hit the recursion limit for long lists. Tail-recursive version is 73 bytes:

(load library)(d E(q((L A)(i(i L(even?(h L))L)(E(t L)(c(h L)A))(reverse A

or ungolfed:

(load library)
(def takewhile-even
 (lambda (ls accum)
  (if
   (if ls (even? (head ls)) ls)
   (takewhile-even
    (tail ls)
    (cons (head ls) accum))
   (reverse accum))))

Note #2: The specification of "take while even" actually costs bytes in tinylisp: even? isn't built-in, so we have to load the library (which is expensive) or reimplement the function (which is worse). Generic takewhile with the predicate as a second argument is only 46 bytes:

(d T(q((L P)(i(i L(P(h L))L)(c(h L)(T(t L)P))(

or ungolfed:

(load library)
(def takewhile
 (lambda (ls predicate)
  (if
   (if ls (predicate (head ls)) ls)
   (takewhile (tail ls) predicate)
   nil)))

(I think I may have my next standard library function here...)

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

Java 8, 79 71 bytes

l->{int i=0;for(int n:l){if(n%2>0)return l.subList(0,i);i++;}return l;}

Explanation:

Try it here.

l->{             // Method with ArrayList<Integer> as parameter and List as return-type
  int i=0;       //  Index-integer
  for(int n:l){  //  Loop over the input-List
    if(n%2>0)    //   If the current item is odd:
      return l.subList(0,i);
                 //    Return a sub-List from 0 through index `i` (exclusive)
    i++;         //   At the end of every iteration: increase index `i` by 1
  }              //  End of loop
  return l;      //  If the input-List was empty or contained no odd values, return itself
}                // End of method
\$\endgroup\$
0
\$\begingroup\$

Perl 5, 18 + 1 (for a) = 19 bytes

Uses -aE instead of -ae.

$_%2?die:say for@F
\$\endgroup\$
0
\$\begingroup\$

Stax, 9 bytes

{O{|e*cf}

This is a block (equivalent to a function) that takes a list and returns a list on the top of the stack. The link below attaches some footers to output the list.

Run and debug online!

Explanation

{O{|e*cf}
{       }    Define a block
 O           Put 1 under top of stack, used as an accumulator
  {    f     Filter array with accumulator
   |e        True if array element is even, false if odd
     *c      `And` with accumulator
\$\endgroup\$
2
  • \$\begingroup\$ Does packing not save any bytes? \$\endgroup\$ Commented Mar 11, 2018 at 11:18
  • \$\begingroup\$ Packed content cannot be directly copied to a program as a block that can be called. \$\endgroup\$ Commented Mar 11, 2018 at 11:41
0
\$\begingroup\$

Add++, 14 bytes

L*,bU1€+2↑%1€_

Try it online!

How it works

L*,		; Declare 'lambda 1' that returns the stack
		; Example argument:		[[12 14 16 17 18 20]]
	bU	; Unpack;		STACK = [12 14 16 17 18 20]
	1€+	; Increment each;	STACK = [13 15 17 18 19 21]
	2↑%	; Takewhile odd;	STACK = [13 15 17]
	1€_	; Decrement each;	STACK = [12 14 16]
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Why the downvote? Is there anything wrong with this answer? \$\endgroup\$ Commented Mar 11, 2018 at 17:51
  • 1
    \$\begingroup\$ I don't see anything wrong with it, so I've upvoted to neutralize the unexplained downvote. \$\endgroup\$ Commented Mar 12, 2018 at 15:59
0
\$\begingroup\$

Javascript (ES2015) , 42 Bytes

I wasn't sure if the expected implementation was of the actual higher order function or the special case of getting a list of all even numbers, so i did both. Byte count is for longest of the two (higher order)

Even numbers (39 bytes)

l=>(o=[],l.every(v=>~v%2&&o.push(v)),o)

Higher order function:

f=>l=>(o=[],l.every(v=>f(v)&&o.push(v)),o)

higher order function called using curry style syntax

f(predicate)(list) => list
\$\endgroup\$

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.