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]
[25, 30, 25, 60, 25]
[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

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.


]&:46*#;_$v\+1\; +1\_;#+fe;#<\v ^_v#!4:\_;#2:<;\ >0>.@  Try it online! Perl 6, 54 52 bytes {$_>5&.grep(*>29)>2}o{any kv classify $+=25>*,0,|$_}


Try it online!

• I'd love to read an explanation of this code!
– Lynn
Apr 24, 2018 at 12:47

K (ngn/k), 3832 30 bytes

{+/7<,/4_'*\'|:',\+/x>/:24 29}


Try it online!

Julia 0.6, 49 bytes

T->reduce((x,y)->y>24?(2+4(y>29))x%864:x>0,1,T)<1


Try it online!

The popular reduce solution from Udo Borkowski. The final <1 limits the output to true/false. We can remove it for 47 bytes, but the output will then be either false or 0 (varying) for, well, false, and a non-zero number for true.

Alternate version (equivalent) based on G B's Ruby implementation (1 byte longer):

T->(x=1;any(y->(x=y>24?(2+4(y>29))x%864:x>0)<1,T))


Try it online!

Explanation for either version:

function u_explained(temps)
x = 1
for y in temps
if y > 24
val = 2 + (y > 29 ? 4 : 0) #2 for 25 to 29, 6 for 30 and above
x = val * x
#If we've reached 5 "summery" days (2^5) of which at least 3 are
# "tropical" (3^3), then x will be a multiple of 2^5*3^3
# If we've reached there, make x 0. Else, keep as is.
x = x % 864
else
#found non-summery day, reset non-zero values into 1 (true), but keep 0 as 0 (false)
x = x > 0
end
end
return x == 0
end


Older solution:

75 bytes

T->(l=endof(T))>4&&any(prod(1+sign(T[i:j]÷5-5))>7 for i=1:l-4 for j=i+4:l)


Try it online!

(+13 bytes to fix buggy behaviour for test cases 2 and 9)

Julia port of Jonathan Allan's brilliant Jelly solution. Probably not optimal, I just found the method used so neat that I had to try it.

• 47 bytes: T->reduce((x,y)->y<25?x>0:(2+(y<30))x%72,1,T)<1 - unfortunately only one of the golfs I used in JavaScript and in C can be used in Julia. Mar 30 at 23:07

Regex (ECMAScript+(?^=)RME), 34 bytes

((:x{25,}){5,})(?^1=(:.*x{30}){3})


Takes its input in unary, as a concatenation of strings of x characters whose lengths represent the numbers, separated and enclosed on both sides by : characters. Example: :xxx:x:xx: represents 3,1,2.

Try it on replit.com - ECMAScript+(?^=) (RegexMathEngine -xli)

(                # \1 = the following:
(
:x{25,}  # Match and consume a list element that's ≥ 25
){5,}        # Loop the above at least 5 times, as many times as possible
)
(?^1=            # Lookinto - match against the contents of \1
(
:.*      # Skip to any list element (completing the match of any
# previously partially-consumed list element), putting it in tail
# (can start in the middle of it and this is still fine, because
# we only need to assert that it's ≥ 30)
x{30}    # Assert tail ≥ 30; tail -= 30
# No need to consume the rest of tail if it's > 30, because the
# ":.*" part will make sure that we finish matching at the end
# of this list element before skipping to a subsequent one.
){3}         # Loop the above 3 times
)


Regex (ECMAScript or better), 38 bytes

(?=(:x{25,}){5,}(.*))(:.*x{30}){3}.*\2


Try it online! - ECMAScript (SpiderMonkey)
Try it online! - ECMAScript 2018 (Node.js)
Try it online! - Perl
Try it online! - Java
Try it online! - Boost
Try it online! - Python
Try it online! - Ruby
Try it online! - PCRE
Try it online! - .NET
Try it on replit.com - ECMAScript (RegexMathEngine)

(?=
(
:x{25,}  # Match and consume a list element that's ≥ 25
){5,}        # Loop the above at least 5 times, as many times as possible
(.*)         # \2 = the remainder of the string
)
(
:.*          # Skip to any list element (completing the match of any
# previously partially-consumed list element), putting it in tail
# (can start in the middle of it and this is still fine, because
# we only need to assert that it's ≥ 30)
x{30}        # Assert tail ≥ 30; tail -= 30
# No need to consume the rest of tail if it's > 30, because the
# ":.*" part will make sure that we finish matching at the end
# of this list element before skipping to a subsequent one.
){3}             # Loop the above 3 times
.*\2             # Assert that at some subsequent position, \2 can be matched,
# demonstrating that the 3 loop iterations above only matched
# list elements that occurred within the same range of the string
# as that matched by the 5 loop iterations at the beginning.


While golfing this, I found a bug in Ruby's regex engine triggered by 39 byte version: Try it online! / Attempt This Online! - it gives false negatives on all of the truthy test cases, while working fine in all the other regex engines.

JavaScript (ES6), 44 bytes

a=>a.reduce((b,c)=>c<25?!!b:b*(2^c<30)%72,1)


Try it online!

This is based on Udo Borkowski's JavaScript answer which is 49 bytes. The extra golfs are:

1. Change (c<30?2:6) to (c<30?2:3), because multiplying by both $$\2\$$ and $$\3\$$ simultaneously is redundant and doesn't keep track of any more information than if we just multiply by two different primes. Thus instead of 864, we can use 108 as our magic number, as the sum of the multiplicities of $$\2\$$ and $$\3\$$ is now equal to the previous multiplicity of $$\2\$$.
2. Change (c<30?2:3) to (c<30?3:2), thus getting 72 as our magic number instead of 108, saving 1 byte.
3. Change (c<30?3:2) to (2^c<30), taking advantage of bitwise ^ having a lower operator precedence than the < comparison operator. This saves another 2 bytes.
4. Move b>0 from the ternary condition, to its truthy argument. This saves another 2 bytes.

This is still "inverted logic", returning falsey for a "Contains a Heat Wave" and truthy for "No Heat Wave". But as a result of change #3, the return value for "Contains a Heat Wave" is sometimes 0 and sometimes false. This can be cleaned up by !, taking it to 45 bytes: Try it online!

The original explanation (edited to reflect the changes):

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 $$\3\$$. If a number $$\≥ 30\$$ is seen, the reduce is multiplied by $$\2\$$. If a number $$\< 25\$$ is seen the reduce starts again at $$\1\$$. If the reduce is divisible by $$\72=2×2×2×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.

Python 2, 59 bytes

lambda a:reduce(lambda b,c:[b*(2+(c<30))%72,b>0][c<25],a,1)


Try it online!

A port of the above. 4 bytes shorter than Udo Borkowski's Python 2 answer which is 63 bytes.

Clean True/False output is 61 bytes: Try it online!

Python 3.8+, 62 59 bytes

lambda a,b=1:[b:=[b*(2+(c<30))%72,b>0][c<25]for c in a][-1]


Unfortunately reduce was moved into the functools library in Python 3. So, this uses a list comprehension workaround to match the Python 2 version's length.

Clean True/False output is 61 bytes: Try it online! / Attempt This Online!

Python 2, 54 bytes

b=1
for c in input():b=[b*(2+(c<30))%72,b>0][c<25]
1/b


Try it online!

This full program outputs via its exit-code:

• 1 (the program raised a ZeroDivisionError) if the list contains a heat wave
• 0 (the program exited normally) if it does not

Python 3+, 60 bytes

Try it online! - Same as the Python 2 version above, but using eval(input()) in place of input().

Python 3.8+, 59 bytes

for c in eval(input())+[b:=1]:b=[b*(2+(c<30))%72,b/b][c<25]


Alternative 59 bytes:

b=1
for c in eval(input()):b=[b:=b*(2+(c<30))%72,b/b][c<25]


Perl 5-pa, 52 bytes

map{$_<25?$w=$h=0:$w++;$h+=$_>29;$\|=$w>4&&$h>2}@F}{  Try it online! Java 8, 91 bytes h->{int e=0,a=0,t=0;for(int i:h)t=(e=i<25?0:e+1)>4&(a=i<25?0:i<30?a:a+1)>2?1:t;return t>0;}  Hopefully we'll have a heat wave here in The Netherlands soon, since it's currently 13 °C again (even though it was 24 °C this weekend..) Try it online. Explanation: h->{ // Method with integer-array parameter and boolean return-type int e=0, // Amount of subsequent 25+ days, starting at 0 a=0, // Amount of 30+ days in the current 'heat wave', starting at 0 t=0; // Result-flag, starting at 0 for(int i:h) // Loop over the input-array t= // Change the flag to: (e=i<25? // If the current temperature is below 25 °C 0 // Reset e to 0 : // Else (temperature is 25+ °C): e+1) // Increase e by 1 >4 // Validate if e is at least 5 now &(a=i<25? // If the current temperature is below 25 °C 0 // Reset a to 0 :i<30? // Else if the current temperature is [25,29] °C a // Leave a the same : // Else (temperature is 30+ °C): a+1) // Increase a by 1 >2? // Validate if a is at least 3 now: // If there is a 'heat wave': 1 // Change the flag t to 1 : // Else: t; // Leave the flag t unchanged return t>0;} // Return whether the flag t is 1 now  J, 35 bytes 1#.(1,2~:/\24<])(2<1#.29<]*4<#);.1]  Try it online! Returns 0 for Falsy and positive integer for Truthy I feel it's too descriptive, so it's certainly golfable. Explanation: I split x u;.1 ythe input list of values into sublists that are smaller or greater/equal to 25. x is a binary mask denoting the intervals, y is the input list (1,2~:/\24<]) finds if each item is greater or equal to 25; then marks the boundaries of the intervals and prepends 1 to the list for the start.  (1,2~:/\24<]) 1 1 25 30 25 30 25 25 25 25 25 25 25 25 40 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 ((1,2~:/\24<])<;.1]) 1 1 25 30 25 30 25 25 25 25 25 25 25 25 40 1 1 ┌───┬──────────────────────────────────────┬───┐ │1 1│25 30 25 30 25 25 25 25 25 25 25 25 40│1 1│ └───┴──────────────────────────────────────┴───┘  (2<1#.29<]*4<#) Checks if the length # of the sublist is at least 5 and sets all items to 0 if not by multiplying the list by the result of the check; then checks if there are 3 or more items that are greater or equal to 30.  ((1,2~:/\24<])(2<1#.29<]*4<#);.1]) 1 1 25 30 25 30 25 25 25 25 25 25 25 25 40 1 1 0 1 0  1#. adds up the partial results ><>, 64 bytes 00>l3(?^$:1+{:64*)?v~~~~
^<v?)4:+1$~$?)+fe<
)?v^>$:@2 ;n< 0<  Keeps track of the current number of summer days and tropical days, resets when a regular day is encountered. For every summer day it checks if the requirements for a heat wave is met. 05AB1E, 18 bytes .γ25@}ʒg5@}30@O3@à  Explanation: .γ } # Group the (implicit) input-list by sections of: 25@ # >= 25 ʒ } # Then only leave groups of: g5@ # At least 5 items 30@ # Check for each remaining value if its >= 30 (1 if truthy; 0 if falsey) O # And get the amount of truthy values per group by taking the sum 3@ # Check if that amount is >= 3 for each à # And check if any are truthy by taking the maximum # (which is output implicitly as result)  APL(NARS), 100 char, 200 bytes ∇r←f w;c;C;k;i;x r←i←c←C←0⋄k←≢w →0×⍳k<i+←1⋄→3×⍳∼25>x←i⊃w⋄c←C←0⋄→2 c+←1⋄C+←x≥30⋄→2×⍳∼(c≥5)∧C≥3 r←1 ∇  I find useful traslate program construct if() with "→LineNumber×⍳∼" test:  f¨(,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) 0 0 0 0 0 0 0 0 0 0 0 0 f¨(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) 1 1 1 1 1 1 1 1 1 1 1 1  If it is better I write less test space someone say that to me... • Why do you localise your variables? The program will certainly work without ;c;C;k;i;x – Adám Feb 17, 2019 at 17:20 • They are local v – user58988 Feb 18, 2019 at 22:57 • @Adám They are local variables, if they are defined out that function, and are not declared local in the function, I suppose they could change what not have to change (a variable out the function) – user58988 Feb 18, 2019 at 23:05 • So what? This is code golf. Code quality is of no importance at all. – Adám Feb 18, 2019 at 23:15 • @Adám yes formally correct and without possible Undefined Behaviour is a prerequisite of one function they came first than codegolf – user58988 Feb 18, 2019 at 23:35 Powershell, 75 73 bytes. -2 bytes thanks to Veskah. based on Javascript by @Arnauld $a=$b=0;$args|?{if($_-ge25){++$a-ge5-band($b+=$_-ge30)-ge3}else{$a=$b=0}}


returns an array or $null. Save as get-heatWave.ps1 and test with script https://regex101.com/r/lXdvIs/2 $t = @(
@(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)
)

$f = @( @(30), @(31, 29, 29, 28, 24, 23, 29, 29, 26, 27, 33, 20, 26, 26, 20, 30), @(29, 29, 29, 47, 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) ) "Should be$true"
$t | % { [bool](.\get-heatWave.ps1 @_) } "Should be$false"
\$f | % {
[bool](.\get-heatWave.ps1 @_)
}


C# (Visual C# Compiler), 114 bytes

using System.Linq;s=>s.Select((a,b)=>s.Skip(b).TakeWhile(c=>c>24)).Any(a=>a.Count()>4&&a.Where(b=>b>29).Count()>2)


Try it online!

C# (.NET Core), 81 bytes

Without LINQ.

a=>{int b=0;foreach(int i in a){b+=i<25?-b:i>29?11:1;if(b>34)return 1;}return 0;}


Try it online!