70
\$\begingroup\$

Inspired by, and in memory of, my dear friend and colleague,

Dan Baronet

Dan Baronet, 1956 – 2016. R.I.P.

He found the shortest possible APL solution to this task:

Task

Given a Boolean list, count the number of trailing truth values.

Example cases

{}0

{0}0

{1}1

{0, 1, 1, 0, 0}0

{1, 1, 1, 0, 1}1

{1, 1, 0, 1, 1}2

{0, 0, 1, 1, 1}3

{1, 1, 1, 1, 1, 1}6

asked Nov 6, 2016 at 12:35
\$\endgroup\$
7
  • \$\begingroup\$ Can we take the list as a string of zeros and ones? e.g. 01100? \$\endgroup\$ Commented Nov 6, 2016 at 12:57
  • \$\begingroup\$ @Adnan only if that is the most normal way for your language to represent boolean lists. \$\endgroup\$ Commented Nov 6, 2016 at 15:42
  • 78
    \$\begingroup\$ Sorry for your loss. \$\endgroup\$ Commented Nov 6, 2016 at 17:03
  • 10
    \$\begingroup\$ @MartinEnder Thank you. It will be tough going forward. Dan taught me all I needed to know to work for Dyalog. \$\endgroup\$ Commented Nov 6, 2016 at 17:32
  • 7
    \$\begingroup\$ Farewell to Dan. RIP... \$\endgroup\$ Commented Nov 7, 2016 at 12:46

64 Answers 64

1
2 3
42
\$\begingroup\$

Dyalog APL, (削除) 6 (削除ここまで) 2 bytes

⊥⍨

Test it on TryAPL.

How it works

(uptack, dyadic: decode) performs base conversion. If the left operand is a vector, it performs mixed base conversion, which is perfect for this task.

For a base vector b = bn, ⋯, b0 and a digit vector a = an, ⋯, a0, b ⊥ a converts a to the mixed base b, i.e., it computes b0⋯bn-1an + ⋯ + b0b1a2 + b0a1 + a0.

Now, (tilde dieresis, commute) modifies the operator to the left as follows. In a monadic context, it calls the operator with equal left and right arguments.

For example, ⊥⍨ a is defined as a ⊥ a, which computes a0⋯an + ⋯ + a0a1a2 + a0a1 + a0, the sum of all cumulative products from the right to the left.

For k trailing ones, the k rightmost products are 1 and all others are 0, so their sum is equal to k.

answered Nov 6, 2016 at 15:22
\$\endgroup\$
4
  • 16
    \$\begingroup\$ Hint: Dan did it in only two bytes. \$\endgroup\$ Commented Nov 6, 2016 at 17:27
  • 4
    \$\begingroup\$ Mixed base conversion! That's clever. \$\endgroup\$ Commented Nov 6, 2016 at 18:03
  • 1
    \$\begingroup\$ Oh. Mixed base conversion, how it strikes again. \$\endgroup\$ Commented Nov 6, 2016 at 18:39
  • 1
    \$\begingroup\$ Bravo! In fact, because of Dan, we special-cased b⊥b and ⊥⍨b giving up to infinite speed-up. \$\endgroup\$ Commented Nov 6, 2016 at 19:18
19
\$\begingroup\$

JavaScript (ES6), 21 bytes

f=l=>l.pop()?f(l)+1:0

Test cases

f=l=>l.pop()?f(l)+1:0
console.log(f([])); // → 0
console.log(f([0])); // → 0
console.log(f([1])); // → 1
console.log(f([0, 1, 1, 0, 0])); // → 0
console.log(f([1, 1, 1, 0, 1])); // → 1
console.log(f([1, 1, 0, 1, 1])); // → 2
console.log(f([0, 0, 1, 1, 1])); // → 3
console.log(f([1, 1, 1, 1, 1, 1])); // → 6

answered Nov 6, 2016 at 13:04
\$\endgroup\$
3
  • \$\begingroup\$ How does this work? How does f(l)+1 return a value > 2? \$\endgroup\$ Commented Jun 4, 2018 at 14:46
  • \$\begingroup\$ @Oliver This is a recursive process, evaluated as l.pop()?(l.pop()?(l.pop()?(...etc...)+1:0)+1:0)+1:0. \$\endgroup\$ Commented Jun 4, 2018 at 14:51
  • \$\begingroup\$ I see. Thanks for the explanation. \$\endgroup\$ Commented Jun 4, 2018 at 14:53
12
\$\begingroup\$

Brachylog, (削除) 7 (削除ここまで) (削除) 6 (削除ここまで) 5 bytes

@]#=+

Try it online!

Explanation

@] A suffix of the Input...
 #= ...whose elements are all equal
 + Sum its elements

Since @] - Suffix starts from the biggest suffix all the way up to the smallest one, it will find the longest run first.

answered Nov 6, 2016 at 12:58
\$\endgroup\$
0
12
\$\begingroup\$

Jelly, 4 bytes

ŒrṪP

Try it online! or Verify all test cases.

For the case where the list is empty, there are some curious observations. First, run-length encoding the empty list [] returns another empty list []. Then retreiving the last element from that using tail returns 0 instead of a pair [value, count] which are the regular elements of a run-length encoded array. Then product P returns 0 when called on 0 which is the expected result.

Explanation

ŒrṪP Main link. Input: list M
Œr Run-length encode
 Ṫ Tail, get the last value
 P Product, multiply the values together
answered Nov 6, 2016 at 12:50
\$\endgroup\$
4
  • \$\begingroup\$ Alternatively, ŒgṪS works, too! \$\endgroup\$ Commented Nov 6, 2016 at 13:20
  • \$\begingroup\$ It gives the right output for the empty list as input, but I'm surprised given the dissection. Would you mind walking through that special case? \$\endgroup\$ Commented Nov 6, 2016 at 13:25
  • \$\begingroup\$ @PeterTaylor I'm surprised too that it worked. Also, I just noticed that the first link has the wrong code. \$\endgroup\$ Commented Nov 6, 2016 at 13:32
  • \$\begingroup\$ @PeterTaylor in Jelly is implemented as: lambda z: iterable(z).pop() if iterable(z) else 0. iterable when called on a list just returns the list, and the empty list is of course falsy. \$\endgroup\$ Commented Nov 6, 2016 at 13:36
11
\$\begingroup\$

Haskell, (削除) 26 (削除ここまで) 25 bytes

a%b|b=1+a|0<3=0
foldl(%)0

Usage:

Prelude> foldl(%)0 [True,False,True,True]
2

Pointfree version (26 bytes):

length.fst.span id.reverse

Using an integer list instead of a bool list (21 bytes, thanks to Christian Sievers):

a%b=b*(a+1)
foldl(%)0

Usage:

Prelude> foldl(%)0 [1,0,1,1]
2

Pointfree version (25 bytes)

sum.fst.span(==1).reverse
answered Nov 6, 2016 at 12:42
\$\endgroup\$
1
  • \$\begingroup\$ For integer lists the foldl idea works with a%b=b*(a+1) \$\endgroup\$ Commented Dec 7, 2016 at 16:09
10
\$\begingroup\$

CJam (8 bytes)

{W%0+0#}

Online test suite

Dissection

{ e# begin a block
 W% e# reverse the array
 0+ e# append 0 so there's something to find
 0# e# find index of first 0, which is number of nonzeros before it
}
answered Nov 6, 2016 at 13:29
\$\endgroup\$
10
\$\begingroup\$

05AB1E, (削除) 12 (削除ここまで) (削除) 10 (削除ここまで) (削除) 6 (削除ここまで) 5 bytes

Saved 1 byte thanks to carusocomputing.

Î0¡¤g

Try it online!

Explanation

Î # push 0 and input
 0¡ # split on 0
 ¤ # take last item in list
 g # get length
answered Nov 6, 2016 at 12:49
\$\endgroup\$
4
  • \$\begingroup\$ 0¡¤g is four bytes. \$\endgroup\$ Commented Nov 7, 2016 at 15:44
  • \$\begingroup\$ @carusocomputing: Nice! It wasn't yet clarified if string input was okay when I wrote this, but I see now that it is :) \$\endgroup\$ Commented Nov 7, 2016 at 15:49
  • \$\begingroup\$ J0¡¤g is also still shorter ;). \$\endgroup\$ Commented Nov 7, 2016 at 15:54
  • \$\begingroup\$ @carusocomputing: Unfortunately we need Î to handle the empty input, but it's still a byte saved thanks :) \$\endgroup\$ Commented Nov 7, 2016 at 15:54
9
\$\begingroup\$

Python, 31 bytes

lambda a:(a[::-1]+[0]).index(0)
answered Nov 6, 2016 at 15:58
\$\endgroup\$
9
\$\begingroup\$

Retina, (削除) 7 (削除ここまで) 5 bytes

r`1\G

Try it online! (The first line enables a linefeed-separated test suite.)

Defining the input format for Retina isn't entirely unambiguous. Since Retina has no concept of any type except strings (and also no value that can be used for our usual definition of truthy and falsy), I usually use 0 and 1 (or something positive in general) to correspond to truthy and falsy, as they represent zero or some matches, respectively.

With single-character representations, we also don't need a separator for the list (which in a way, is more the more natural list representation for a language that only has strings). Adám confirmed that this is an acceptable input format.

As for the regex itself, it matches from right to left and \G anchors each match to the previous one. Hence, this counts how many 1s we can match from the end of the string.

answered Nov 6, 2016 at 17:09
\$\endgroup\$
1
  • \$\begingroup\$ "Yes, for Retina, being that it handles only strings, I think a "01" or "FT" string is in order. \$\endgroup\$ Commented Nov 6, 2016 at 17:23
8
\$\begingroup\$

MATL, 4 bytes

PYps

Try it online!

P % Flip
 Yp % Cumulative product
 s % Sum
answered Nov 6, 2016 at 17:03
\$\endgroup\$
0
7
\$\begingroup\$

Jelly, 4 bytes

ṣ0ṪL

TryItOnline! , or all tests

How?

ṣ0ṪL - Main link: booleanList
ṣ0 - split on occurrences of 0 ([] -> [[]]; [0] -> [[],[]]; [1] -> [[1]]; ...)
 Ṫ - tail (rightmost entry)
 L - length
answered Nov 6, 2016 at 14:23
\$\endgroup\$
7
\$\begingroup\$

Mathematica, (削除) 25 (削除ここまで) 24 bytes

Fold[If[#2,#+1,0]&,0,#]&
answered Nov 6, 2016 at 13:18
\$\endgroup\$
1
  • 3
    \$\begingroup\$ Just recording a port of Dan's cool mixed-base solution: FromDigits[b=Boole@#,MixedRadix@b]& (35 bytes). \$\endgroup\$ Commented Nov 7, 2016 at 7:31
6
\$\begingroup\$

J, (削除) 9 (削除ここまで) 3 bytes

#.~

This is reflexive mixed base conversion. Because this is the same as mixed base conversion. Again.

Test cases

 v =: #.~
 ]t =: '';0;1;0 1 1 0 0;1 1 1 0 1;1 1 0 1 1;0 0 1 1 1;1 1 1 1 1 1
++-+-+---------+---------+---------+---------+-----------+
||0|1|0 1 1 0 0|1 1 1 0 1|1 1 0 1 1|0 0 1 1 1|1 1 1 1 1 1|
++-+-+---------+---------+---------+---------+-----------+
 v&.> t
+-+-+-+-+-+-+-+-+
|0|0|1|0|1|2|3|6|
+-+-+-+-+-+-+-+-+
 (,. v&.>) t
+-----------+-+
| |0|
+-----------+-+
|0 |0|
+-----------+-+
|1 |1|
+-----------+-+
|0 1 1 0 0 |0|
+-----------+-+
|1 1 1 0 1 |1|
+-----------+-+
|1 1 0 1 1 |2|
+-----------+-+
|0 0 1 1 1 |3|
+-----------+-+
|1 1 1 1 1 1|6|
+-----------+-+
answered Nov 6, 2016 at 15:30
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Hint: This can be done in only 3 bytes, using the J translation of Dan's solution. \$\endgroup\$ Commented Nov 6, 2016 at 17:25
  • 1
    \$\begingroup\$ @Adám I tried looking for a solution. Didn't think of base conversion. That's really quite clever of him! \$\endgroup\$ Commented Nov 6, 2016 at 18:44
  • 1
    \$\begingroup\$ Yes. That was Dan. :-( \$\endgroup\$ Commented Nov 6, 2016 at 19:20
6
\$\begingroup\$

Pyth, 6 bytes

x_+0Q0

Try it here!

Appends a 0, reverses and finds the index of the first 0

answered Nov 6, 2016 at 12:57
\$\endgroup\$
1
  • \$\begingroup\$ @Jakube fixed now - different algorithm \$\endgroup\$ Commented Nov 7, 2016 at 9:54
5
\$\begingroup\$

C90 (gcc), 46 bytes

r;main(c,v)int**v;{while(0<--c&*v[c])r++;c=r;}

Input is via command-line arguments (one integer per argument), output via exit code.

Try it online!

How it works

r is a global variable. Its type defaults to int and, being global, it value defaults to 0.

The function argument c defaults to int as well. It will hold the integer n + 1 for arrays of n Booleans; the first argument of main is always the path of the executable.

The function argument v is declared as int**. The actual type of v will be char**, but since we'll only examine the least significant bit of each argument to tell the characters 0 (code point 48) and 1 (code point 49) apart, this won't matter on little-endian machines.

The while loop decrements c and compares it to 0. Once c reaches 0, we'll break out of the loop. This is needed only if the array contains no 0's.

As long as 0<--c returns 1, we takes the cth command-line argument (v[c]) and extract its first character with by dereferencing the pointer (*). We take the bitwise AND of the Boolean 0<--c and the code point of the character (and three garbage bytes that follow it), so the condition will return 0 once a 0 is encountered, breaking out of the loop.

In the remaining case, while the command-line arguments are 1, r++ increments r by 1, thus counting the number of trailing 1's.

Finally, c=r stores the computed value of r in c. With default settings, the compiler optimize and remove the assignment; it actually generates the movl %eax, -4(%rbp) instruction. Since ret returns the value of the EAX register, this generates the desired output.

Note that this code does not work with C99, which returns 0 from main if the end of main is reached.

answered Nov 7, 2016 at 2:18
\$\endgroup\$
3
  • \$\begingroup\$ Isn´t argc at least 1 (with argv[0] containing the file name)? You could save one byte with --c&& instead of 0<--c&. gcc´s exit code is taken from argc? Neat. \$\endgroup\$ Commented Dec 7, 2016 at 17:50
  • \$\begingroup\$ @Titus That won't work. *v[c] is the code point of 1 or 0, so it's either 49 or 48 and thus always truthy. \$\endgroup\$ Commented Dec 7, 2016 at 18:19
  • \$\begingroup\$ With C89 and C90, gcc returns whatever is in RAX at that moment. C99 always returns 0 from main if the end is reached. \$\endgroup\$ Commented Dec 7, 2016 at 18:22
4
\$\begingroup\$

k, 6 bytes

+/&\|:

This function composition translates to sum mins reverse in q, the language's more readable sibling, where mins is a rolling minimum.

answered Nov 6, 2016 at 15:18
\$\endgroup\$
2
  • \$\begingroup\$ Can the : be dropped? \$\endgroup\$ Commented Oct 5, 2018 at 6:33
  • 1
    \$\begingroup\$ A port of APL version is possible in ngn/k for 5 bytes. \$\endgroup\$ Commented Feb 25, 2021 at 0:08
4
\$\begingroup\$

R, (削除) 40 39 (削除ここまで) 25 bytes

Completely reworked solution thanks to @Dason

sum(cumprod(rev(scan())))

Read input from stdin, reverse the vector and if the first element of is !=0 then output the the first length of the run-length encoding (rle), else 0.

answered Nov 6, 2016 at 14:02
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You can save a byte by changing the second line to ifelse(r$v,r$l,0)[1]. (Vectorized if, and then take the first element.) \$\endgroup\$ Commented Nov 6, 2016 at 15:10
  • 1
    \$\begingroup\$ no need for the iflelse - just multiply r$v and r$l. \$\endgroup\$ Commented Nov 8, 2016 at 15:22
  • \$\begingroup\$ But the sum(cumprod(rev(.))) route should save a lot of bytes anyways \$\endgroup\$ Commented Nov 8, 2016 at 15:23
3
\$\begingroup\$

Haskell, 24 bytes

foldl(\a b->sum[a+1|b])0

Iterates over the list, adding one for each element, resetting to 0 after it hits a False.

16 bytes with 0/1 input:

foldl((*).(+1))0

If the list were guaranteed non-empty, we could get 14 bytes:

sum.scanr1(*)1

This computes the cumulative product from the back, then sums them. The cumulative product remains 1 until a 0 is hit, and then becomes 0. So, the 1's correspond to trailing 1's.

answered Nov 6, 2016 at 21:43
\$\endgroup\$
3
\$\begingroup\$

Pyke, (削除) 10 (削除ここまで) 6 bytes

_0+0R@

Try it here!

answered Nov 6, 2016 at 12:54
\$\endgroup\$
3
\$\begingroup\$

C#6, (削除) 103 (削除ここまで) 72 bytes

using System.Linq;
int a(bool[] l)=>l.Reverse().TakeWhile(x=>x).Count();

Using non-generic list beats generic list by 1 byte lol

-31 bytes thanks to Scott

answered Nov 7, 2016 at 12:18
\$\endgroup\$
3
  • \$\begingroup\$ If you use an array of ints, you can get away with int a(int[] l)=>l.Reverse().TakeWhile(i=>i>0).Sum(); \$\endgroup\$ Commented Nov 7, 2016 at 20:52
  • \$\begingroup\$ @Scott Of course what was I thinking... I will stick with bool though. Question specifies boolean list and it's not C. \$\endgroup\$ Commented Nov 8, 2016 at 12:24
  • \$\begingroup\$ Compile to a Func<bool[], int> for 57 bytes i.e. using System.Linq;l=>l.Reverse().TakeWhile(x=>x).Count(); \$\endgroup\$ Commented Nov 8, 2016 at 13:45
3
\$\begingroup\$

Japt -hx, 3 bytes

i ô

Try it online!

Japt's flag combinations rock.

How it works

Ui ô
Ui Insert `undefined` at index 0
ô Split at falsy items
-h Take last element
-x Sum

If we didn't have to handle the special case [], we could get away with 1 byte ô, winning over APL.

answered Jun 1, 2018 at 7:59
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Half the job is done by flags‽ \$\endgroup\$ Commented Jun 1, 2018 at 8:22
2
\$\begingroup\$

Python, 37 bytes

f=lambda l:len(l)and-~f(l[:-1])*l[-1]
answered Nov 6, 2016 at 15:54
\$\endgroup\$
2
\$\begingroup\$

DASH, 16 bytes

@len mstr"1+$"#0

It's not the shortest possible DASH solution, but the shortest possible DASH solution is bugging out on me. I'm posting this novel approach in its place.

Usage:

(@len mstr"1+$"#0)"100111"

Explanation

@( #. Lambda
 len ( #. Get the length of the array after...
 mstr "1+$" #0 #. ... matching the argument with regex /1+$/
 ) #. * mstr returns an empty array for no matches
)
answered Nov 6, 2016 at 18:53
\$\endgroup\$
2
\$\begingroup\$

Scala, 25 bytes

l=>l.reverse:+0 indexOf 0

Ungolfed:

l=>(l.reverse :+ 0).indexOf(0)

Reverses the list, appends a 0 and find the first index of 0, which is the number of elements before the first 0

answered Nov 6, 2016 at 19:31
\$\endgroup\$
2
\$\begingroup\$

Batch, 57 bytes

@set n=0
@for %%n in (%*)do @set/an=n*%%n+%%n
@echo %n%

Takes input as command-line parameters. Works by multiplying the accumulator by the current value before adding it on, so that any zeros in the command line reset the count. Note that %%n is not the same as the n or %n% variable.

answered Nov 6, 2016 at 21:06
\$\endgroup\$
2
\$\begingroup\$

GolfSharp, 14 bytes

n=>n.V().O(F);
answered Nov 6, 2016 at 23:09
\$\endgroup\$
2
\$\begingroup\$

Java 7, 62 bytes

int c(boolean[]a){int r=0;for(boolean b:a)r=b?r+1:0;return r;}

Ungolfed & test code:

Try it here.

class M{
 static int c(boolean[] a){
 int r = 0;
 for (boolean b : a){
 r = b ? r+1 : 0;
 }
 return r;
 }
 public static void main(String[] a){
 System.out.print(c(new boolean[]{}) + ", ");
 System.out.print(c(new boolean[]{ false }) + ", ");
 System.out.print(c(new boolean[]{ true }) + ", ");
 System.out.print(c(new boolean[]{ false, true, true, false, false }) + ", ");
 System.out.print(c(new boolean[]{ true, true, true, false, true }) + ", ");
 System.out.print(c(new boolean[]{ true, true, false, true, true }) + ", ");
 System.out.print(c(new boolean[]{ false, false, true, true, true }) + ", ");
 System.out.print(c(new boolean[]{ true, true, true, true, true, true }));
 }
}

Output:

0, 0, 1, 0, 1, 2, 3, 6
answered Nov 7, 2016 at 10:01
\$\endgroup\$
2
\$\begingroup\$

Perl 5.10, 22 bytes

21 bytes + 1 byte for -a flag. Since the regex-based expression was done... :p

The input values for the array must be separated by a space.

$n++while pop@F;say$n

Try it online!

answered Nov 7, 2016 at 10:55
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Slightly shorter if you take arguments via command line: perl -E '$_++while pop;say' 0 1 1 0 1 1 1 but this doesn't output anything for 0 (not sure if that's a problem though!) \$\endgroup\$ Commented Nov 7, 2016 at 12:43
2
\$\begingroup\$

Perl, 22 bytes

21 bytes of code + 1 byte for -p flag.

s/.(?=.*0)//g;$_=y;1;

To run it :

perl -pE 's/.(?=.*0)//g;$_=y;1;' <<< "0 1 1 0 1 1 1"

(Actually, the format of the input doesn't matter a lot : 0110111, 0 1 1 0 1 1 1, [0,1,1,0,1,1,1] etc. would all work)


18 bytes version from @Dom Hastings but it requires to supply the input as a string of 0 and 1, which isn't allowed :

perl -pE '/1*$/;$_=length$&' <<< '0110111'
answered Nov 6, 2016 at 13:49
\$\endgroup\$
2
  • \$\begingroup\$ Loving that ; trick :) If format is one continuous string: perl -pE '/1*$/;$_=length$&' <<< '0110111' for 18, not sure if that's bending the rules or not though... \$\endgroup\$ Commented Nov 7, 2016 at 12:42
  • \$\begingroup\$ @DomHastings yea, me too! (Thanks Ton for showing me that!) The first and second comments of the question kinda disallow the format of input you need for your solution... But I'll edit my post to suggest your version if the format of the input was more free. \$\endgroup\$ Commented Nov 7, 2016 at 13:39
2
\$\begingroup\$

PHP, 50 bytes

<?=strlen(preg_filter('/.*[^1]/','',join($argv)));

Weirdly my first try with a regex turned out shorter than my try with arrays...
Use like:

php tt.php 1 1 0 1 1
answered Nov 7, 2016 at 16:39
\$\endgroup\$
1
2 3

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.