# Background

The Royal Netherlands Meteorological Institute defines a heat wave* as a series of at least 5 consecutive days of ≥25°C weather (“summery weather”), such that at least 3 of those days are ≥30°C (“tropical weather”).

The tropical weather doesn't have to be measured consecutively: for example: 30, 25, 30, 26, 27, 28, 32, 30 is a 8-day long heat wave with 4 days of tropical weather.

*(Well, by Dutch standards.)

# Challenge

Given a non-empty list of positive integers representing Celsius temperature measurements from successive days, decide whether that list contains a heat wave (as per the above definition).

The shortest answer in bytes wins.

# Test cases

Falsey:

[30]
[29, 29, 29, 47, 30]
[31, 29, 29, 28, 24, 23, 29, 29, 26, 27, 33, 20, 26, 26, 20, 30]
[23, 31, 29, 26, 30, 24, 29, 29, 25, 27, 24, 28, 22, 20, 34, 22, 32, 24, 33]
[23, 24, 25, 20, 24, 34, 28, 32, 22, 20, 24]
[24, 28, 21, 34, 34, 25, 24, 33, 23, 20, 32, 26, 29, 29, 25, 20, 30, 24, 23, 21, 27]
[26, 34, 21, 32, 32, 30, 32, 21, 34, 21, 34, 31, 23, 27, 26, 32]
[29, 24, 22, 27, 22, 25, 29, 26, 24, 24, 20, 25, 20, 20, 24, 20]
[23, 33, 22, 32, 30]
[28, 21, 22, 33, 22, 26, 30, 28, 26, 23, 31, 22, 31, 25, 27, 27, 25, 28]
[27, 23, 42, 23, 22, 28]
[25, 20, 30, 29, 32, 25, 22, 21, 31, 22, 23, 25, 22, 31, 23, 25, 33, 23]

Truthy:

[30, 29, 30, 29, 41]
[1, 1, 25, 30, 25, 30, 25, 25, 25, 25, 25, 25, 25, 25, 40, 1, 1]
[31, 34, 34, 20, 34, 28, 28, 23, 27, 31, 33, 34, 29, 24, 33, 32, 21, 34, 30, 21, 29, 22, 31, 23, 26, 32, 29, 32, 24, 27]
[26, 29, 22, 22, 31, 31, 27, 28, 32, 23, 33, 25, 31, 33, 34, 30, 23, 26, 21, 28, 32, 22, 30, 34, 26, 33, 20, 27, 33]
[20, 31, 20, 29, 29, 33, 34, 33, 20]
[25, 26, 34, 34, 41, 28, 32, 30, 34, 23, 26, 33, 30, 22, 30, 33, 24, 20, 27, 23, 30, 23, 34, 20, 23, 20, 33, 20, 28]
[34, 23, 31, 34, 34, 30, 29, 31, 29, 21, 25, 31, 30, 29, 29, 28, 21, 29, 33, 25, 24, 30]
[22, 31, 23, 23, 26, 21, 22, 20, 20, 28, 24, 28, 25, 31, 31, 26, 33, 31, 27, 29, 30, 30]
[26, 29, 25, 30, 32, 28, 26, 26, 33, 20, 21, 32, 28, 28, 20, 34, 34]
[34, 33, 29, 26, 34, 32, 27, 26, 22]
[30, 31, 23, 21, 30, 27, 32, 30, 34, 29, 21, 31, 31, 31, 32, 27, 30, 26, 21, 34, 29, 33, 24, 24, 32, 27, 32]
[25, 33, 33, 25, 24, 27, 34, 31, 29, 31, 27, 23]
• Is the temperature guaranteed to be below 100 Celsius? Apr 23, 2018 at 21:38
• @FryAmTheEggman Well, in the Netherlands, yes :), but I don't want your answer to abuse this fact, so no.
– Lynn
Apr 24, 2018 at 6:42
• @HatWizard Yes, that’s okay. “Crash / don’t crash” is also fine, for example.
– Lynn
Jun 11, 2018 at 14:43
• Hey @Lynn this was a great challenge and still is :-) Jun 19, 2018 at 20:01
• @RolandSchmitz Thank you! I'm happily surprised by the creative answers that came out of it so late into the challenge's lifetime. 🎉
– Lynn
Jun 20, 2018 at 8:25

# C (gcc), 8875 73 bytes

h,e,a;t(int*_){for(h=e=a=0;*_;h+=e>4&a>2)e=*_<25?a=0:++e,a+=*_++>29;e=h;}

Try it online!

• h,e,a;t - nice touch!
– user79465
Apr 23, 2018 at 19:45
• @ceilingcat Thank you. Jun 19, 2020 at 23:40

# Jelly, 15 bytes

:5_5Ṡ‘ẆP«LƊ€>4Ṁ

A monadic link accepting a list of numbers which returns 1 if a heatwave was detected else 0.

Try it online! or see the test-suite.

### How?

The criteria is the existence of a run of more than four values greater than or equal to 25, of which more than two must be greater than or equal to 30.

If we divide through by five the criteria becomes the existence of a run of more than four values greater than or equal to five, of which more than two must be greater than or equal to six.

If we subtract five from these values the criteria becomes the existence of a run of more than four values greater than or equal to zero, of which more than two must be greater than or equal to one.

If we take the sign of these values (getting -1, 0, or 1) the criteria becomes the existence of a run of more than four values not equal to -1, of which more than two must be equal to one.

If we add one to these values (getting 0, 1, or 2) the criteria becomes the existence of a run of more than four values not equal to zero, of which more than two must be equal to two.

The product of a list containing any zeros is zero and the product of a list containing more than two twos (and the rest being ones) is more than four. This means that the criteria on this adjusted list becomes that the minimum of the product and the length is greater than 4.

:5_5Ṡ‘ẆP«LƊ€>4Ṁ - Link: list of numbers
:5              - integer divide by five (vectorises)
_5            - subtract five (vectorises)
Ṡ           - sign {negatives:-1, zero:0, positives:1} (vectorises)
‘          - increment (vectorises)
Ẇ         - all sublists
P        -   product
L      -   length
«       -   minimum
>4  - greater than four? (vectorises) -- 1 if so, else 0
Ṁ - maximum -- 1 if any are 1, else 0

any(\a->sum[1|x<-a,x>29,take 4a<a]>2).scanl(\a t->[0|t>24]>>t:a)[]

Thanks to @flawr and @Laikoni for two bytes each and @xnor for a byte!

Try it online!

Equal length:

any(\a->take 4a<a&&sum a>2).scanl(\a t->[0|t>24]>>sum[1|t>29]:a)[]

Try it online!

# C (clang), 64 bytes

h;o(*t){for(h=1;*t;++t)h=h&&*t<25?1:h*(*t<30?2:6)%864;return!h;}

The function o() returns 1 for a heatwave or 0 else.

Thanks to the magic number 864 and to Udo Borkowski and Mathis for their ideas.

How does if work? Each sequence of numbers is iterated with a reduce operation starting at the reduce value 1. If a number >= 25 is seen the reduce is multiplied by 2. If a number >= 30 is seen the reduce is multiplied by 2 and by 3 = 6. If a number < 25 is seen the reduce starts again at 1. If the reduce is divisible by 864=2*2*2*2*2*3*3*3 then a heatwave is found, and the result of the modulo operation is 0 which results in a reduce value of 0 and in a return value of true.

Try it online!

• Welcome to PPCG. Jun 8, 2018 at 19:16
• Welcome to PPCG! Very nice first answer complete with test case suite! Could you add an explanation so we understand the magic? Jun 8, 2018 at 19:48
• That's a really elegant solution, well done :)
– Lynn
Jun 9, 2018 at 14:48

# Python 3, 79 bytes

lambda T:any(len(s)>4<sum(s+s)for s in bytes(t>29or(t<25)*9for t in T).split())

Try it online!

# APL (Dyalog Classic), 21 20 bytes

1∊8≤4↓⍉×\25 30⍸↑,⍨\⎕

Try it online!

uses ⎕io←1

25 30⍸x is 0 if x<25, 1 if 25≤x<30, or 2 otherwise

we compute cumulative products of these starting from (or equivalently: ending at) all possible locations, discard the first 4 products, and detect the presence of products ≥8 (which is 23)

# Japt, 19 18 bytes

ô                  // Partition the input at every item
<25               // where the value is less than 25.
d_            // Then, return whether any resulting subarray
Ê¨5         // is at least five items long
3§      // has at least three items
Zè¨30 // with a value of at least 30.

I hope I got all the discussions in the comments correctly.
Shaved off one byte thanks to Shaggy.

Try it online!

• Thought this'd work out shorter when I was reading through it but could only manage 18 bytes. Apr 23, 2018 at 20:54
• @Shaggy I thought so too, but I couldn't find a shorter version either. Thanks a lot for the pointer! Apr 23, 2018 at 21:02
• Looks like we're winning this one at the moment :) Apr 23, 2018 at 21:04
• Do the non-ASCII characters not count as multiple bytes?
– sudo
Apr 24, 2018 at 0:43
• @sudo Those symbols are all single-byte. For example, would be 3 bytes, but ¨ is one byte. The symbols used above have been picked for the golfing language exactly for the reason that they're all a single byte. Apr 24, 2018 at 7:39

# PowerShell, 121 bytes

param($a)$b="";($a|%{if($_-ge25){$b+="$_ "}else{$b;$b=""}})+$b|?{(-split$_).count-ge5-and(-split$_|?{$_-ge30}).count-ge3}

PowerShell doesn't have the equivalent of a .some or .every or the like, so this is rolled by hand.

We take input $a as an array of integers. Set helper variable$b to the empty string. Then, loop through every integer in $a. Inside the loop, if the integer is -greaterthanorequal to 25, add it to our potential string$b, otherwise put $b on the pipeline and set it to the empty string. Once outside the loop, array-concatenate the pipeline results with$b, and put those through a Where-Object clause |?{...}. This pulls out those strings that have an element length of -ge5 (based on splitting on whitespace) and a count of temps greater than 30 being -ge3. Those strings are left on the pipeline, so a truthy value is non-empty (see the "verify all test cases" link for truthy/falsey distinction).

• try to use $args instead param($a) and $a Jun 9, 2018 at 6:45 • -2 bytes ...{$a=-split$_;$a.count-ge5-and($a|?{$_-ge30}).count-ge3} Jun 9, 2018 at 8:46
• 109 bytes with arrays. save $args|%{if($_-ge25){$b+=$_}else{,$b;$b=@()}}-E{,$b}-B{,($b=@())}|?{$_.count-ge5-and($_|?{$_-ge30}).count-ge3} as get-heatWave.ps1. Test script regex101.com/r/lXdvIs/2 Jun 9, 2018 at 10:57 • 103 bytes$b=@();$args|%{if($_-ge25){$b+=$_}else{,$b;$b=@()}}-E{,$b}|?{$_.count-ge5-and($_|?{$_-ge30}).count-ge3} Jun 9, 2018 at 11:13
• What does -E do? I'm not familiar with that. Jun 13, 2018 at 15:05

# Jelly, 17 16 bytes

:5_5Ṡṣ-ḤS«LƊ€Ṁ>4

Try it online!

### How it works

:5_5Ṡṣ-ḤS«LƊ€Ṁ>4  Main link. Argument: T (array of temperatures)

:5                Divide each item of T by 5 (integer division).
_5              Subtract 5 from each quotient.
Ṡ             Take the signs.
This maps (-oo,25) to -1, [25,30) to 0, and [30,+oo) to 1.
ṣ-           Split at occurrences of -1.
Ḥ          Double, replacing 1's with 2's.
Ɗ€     Map the three links to the left over each chunk.
S             Take the sum.
L           Take the length.
«            Take the minimum of the results.
Ṁ    Take the maximum.
>4  Test if it's larger than 4.
Note that the sum is larger than 4 if and only if there are more
than two 2's, which correspond to temperatures in [30,+oo).

# Python 2, 86 bytes

lambda l:any(2<s.count('2')*(len(s)>14)for s in[(t>24)+(t>29)for t in l].split('0'))

Try it online!

# JavaScript (ES6), 63 51 bytes

Returns a boolean.

a=>a.some(n=>(n>24?y+=++x&&n>29:x=y=0)>2&x>4,x=y=0)

Try it online!

# 05AB1E, 20 bytes

Œʒ24›DPsO4›*}29›O2›Z

Try it online!

Explanation

Œ                     # push sublists of input
ʒ          }         # filter, keep the lists where:
*          # the product of:
DP               # the product and
sO4›           # the sum compared using greater-than to 4
24›                 # for the elements greater than 24
# is true
# the result is:
Z  # the maximum from the remaining lists where
O     # the sum of
29›      # the elements greater than 29
2›   # is greater than 2

## Batch, 119 bytes

@set h=0
@for %%t in (0 %*)do @if %%t lss 25 (set/as=5,t=3)else set/a"t+=!!t*(29-%%t)>>9,s-=!!s,h+=!(s+t+h)
@echo %h%

Takes input as command-line arguments and outputs 1 for a heatwave otherwise 0.

# Python, 67 bytes

f=lambda l:l>l[:4]and(min(l)>24<sorted(l)[~2]-5)|f(l[1:])|f(l[:-1])

Try it online!

Times out on the longer test cases due to exponential growth. Finds contiguous sublists by repeatedly chopping the first or last element. That 3 days are ≥30°C is checked by looking at the third-largest value sorted(l)[~2]. The base cases could perhaps be shorter by taking advantage of truthy/falsey or terminating with error.

# JavaScript (Node.js), 48 bytes

a=>a.some(x=>x>24?++A>4&(B+=x>29)>2:A=B=0,A=B=0)

Try it online!

Try it online!

# Stax, 23 bytes

Æ7)║▄░Ä╟═╙hⁿ╧\ßY8÷K▌µ½x

Run and debug it at staxlang.xyz! This takes a long time to run, so I disabled auto-run.

### Unpacked (28 bytes) and explanation

:efc%4>nc{24>f=a{29>f%2>|&|&
:e                              Set of all contiguous subarrays
f                             Filter, using the rest of the program as a predicate:
c                              Copy subarray on the stack
%4>                           Five or more elements?
|&        AND
nc                         Copy subarray twice to top
{   f                    Filter:
24>                       Greater than 24?
=                   Equals the original subarray?
|&      AND
a                  Move subarray to top
{   f             Filter:
29>                Greater than 30?
%2>          Length greater than two?
Implicit print if all three conditions are met

This'll print all subarrays that can be counted as heat waves, which will be falsy if and only if none exist.

# Ruby, 89 bytes

->a{(0..a.size).map{|i|(b=a[i..-1].take_while{|t|t>24}).size>4&&b.count{|t|t>29}>2}.any?}

Try it online!

• I believe it fails because in the second truthy case, the +30 days are not all within five days. Apr 23, 2018 at 19:52
• Very nice. You can shave off a few bytes with an each_cons approach - Try it online! Apr 25, 2018 at 3:44

# Husk, 19 bytes

Vo≥3#≥30fo≥5Lġ(±≥25

Try it online!

Using filter (f) is one byte shorter than using checking with a logical and (&), also it would be really nice to get rid of the ± - costing 2 bytes :(

### Explanation

V(≥3#≥30)f(≥5L)ġ(±≥25)  -- example input: [12,25,26,27,28,29,18,24,32]
ġ(    )  -- group by
( ≥25)  -- | greater or equal to 25: [0,1,2,3,4,5,6,0,0,8]
(±   )  -- | sign: [0,1,1,1,1,1,1,0,0,1]
-- : [[12],[25,26,27,28,29,30],[18,24],[32]]
f(   )         -- filter by
(  L)         -- | length: [1,6,2,1]
(≥5 )         -- | greater or equal to 5: [0,2,0,0]
-- : [[25,26,27,28,29,30]]
V(      )               -- does any element satisfy
(  #   )               -- | count occurences where
(   ≥30)               -- | | elements greater or equal to 30
(      )               -- | : [1]
(≥3    )               -- | greater or equal to 3: [0]
-- : 0

## Retina, 31 bytes

G4_+
/\b_{1,24}\b/%)C2_{30}
1

Try it online!

# R, 111 93 71 67 66 bytes

!Reduce(function(i,j)"if"(j<25,!!i,(i*(2+4*!j<30))%%864),scan(),1)

Try it online!

Shameless port of Roland Schmitz's answers. -4 bytes thanks to Roland and -1 thanks to Giuseppe.

Previous version extracted consecutive days>25 using rle and saved a whopping 18 bytes thanks to Giuseppe!

• if you use F instead of T, you can do F=F|"if"(cond,(expr),0) and then return F to save 6-ish bytes. You also have an unnecessary pair of parentheses around (1-z[i]):0 but I think that could just be 1-z[i]:1 anyway to save another couple bytes... May 22, 2018 at 16:24
• ^ I was about to submit the above comment when another idea occurred to me, and I managed to find a sub-100 byte solution! It's function(x,z=rle(x>24)$l){for(i in 1:sum(z|1))F=F|z[i]>4&sum(x[sum(z[1:i])+1-z[i]:1]>29)>2;F} but be careful pasting from PPCG into TIO because sometimes unprintables creep in... May 22, 2018 at 16:26 • This is fantastic! There is probably an even shorter way leveraging Jonathan Allan's math... May 22, 2018 at 16:30 • Nice, you could even save some more bytes, if you simplify the inner part from (i*2*(1+(2*(j>29)))) to (i*(2+4*(j>29))) Jun 9, 2018 at 12:25 • @RolandSchmitz very true! Jun 9, 2018 at 13:30 # Swift 4, 50 bytes {$0.reduce(1){$0>0&&$1<25 ?1:$0*($1<30 ?2:6)%864}}

Try it online!

The closure expression returns 0 for a heatwave or >0 else.

Created in collaboration with Roland Schmitz and Mathis.

How does if work? Each sequence of numbers is iterated with a reduce operation starting at the reduce value 1. If a number >= 25 is seen the reduce is multiplied by 2. If a number >= 30 is seen the reduce is multiplied by 2 and by 3 = 6. If a number < 25 is seen the reduce starts again at 1. If the reduce is divisible by 864=2*2*2*2*2*3*3*3 then a heatwave is found, and the result of the modulo operation is 0 which results in a reduce value of 0. Only when a heat wave was found the reduce can become 0. Once the reduce value is 0 it will be 0 for all future reduces, i.e. also for the end result.

f q|(a,~(_:t))<-span(>24)q=sum[1|x<-a,x>29,take 4a<a]>2||f t

Try it online!

This combines some ideas from previous Haskell answers in a new form along with exit by error code to come out ahead.

### How?

(a,~(_:t))<-span(>24)q puts the prefix of the list which is entirely >24 into a, and then tries to match the remainder of the list to the pattern h:t (dropping one value <= 24 and putting the remaining suffix into t). This pattern match might fail even on truthy inputs, if the heat wave is at the end of the list, which is where the ~ comes in: it forces Haskell to match the rest of the pattern even if _:t can't be matched (an "irrefutable pattern"), in which case t is undefined (i.e. set to _|_) and will error out if we ever try to use it.

Since Haskell has the usual short circuiting on ||, we will only try to evaluate f t on undefined t if there was no heat wave in the list, in which case we exit high. If there was a heat wave, we'll find it and short circuit out, returning True and exiting low.

The irrefutable pattern saves one byte compared to tail, which will similarly fail if called on an empty list:

f q|(a,b)<-span(>24)q=sum[1|x<-a,x>29,take 4a<a]>2||f(tail b)

Try it online!

# Pyth, 23 bytes

f&glT5&>T]25gePPT30SM.:

Try it here

f&glT5&>T]25gePPT30SM.:
f                  SM.:Q   Get the sorted subsequences of the (implicit) input...
&qlT5                     ... with at least 5 elements...
&>T]25               ... all at least 25...
gePPT30        ... where the third to last is at least 30.

# Befunge-98, 61 bytes

]&:46*#;_\$v\+1\;
+1\_;#+fe;#<\v
^_v#!4:\_;#2:<;\
>0>.@

Try it online!