Apr 8, 2018

Every week, the statistical analysis website FiveThirtyEight publishes some riddles. In this week’s riddle, titled When Will The Arithmetic Anarchists Attack?, the challenge is to figure how many dates between 1/1/2000 and 12/31/2099, using the date format `MM/DD/YY`

, meet the following condition:

MM * DD == YY

For example, for the dates January 1, 2001 and February 12, 2024:

01 * 01 == 01 # 01/01/01 02 * 12 == 24 # 02/12/24

Sticking with their presentation of the problem, which you should definitely read as it’s far more creative than my summary of it, we will call each match an “attack”.

The specific questions are:

- How many attacks will happen between the beginning of 2001 and the end of 2099?
- What year will see the most vandalism?
- What year will see the least vandalism?
- What will be the longest gap between attacks?

I used to Python with a pandas DataFrame to figure this out.

```
from datetime import date, timedelta
from collections import defaultdict
import numpy as np
import pandas as pd
day = date(2000,1,1)
lastday = date(2099,12,31)
attacks = defaultdict(int)
while day <= lastday:
m = day.month
d = day.day
y = day.year - 2000
if m*d == y:
attacks[day.year] += 1
day = day + timedelta(days=1)
df = pd.DataFrame.from_dict(attacks, orient="index")
df.columns = ["Attacks"]
```

The head and the tail of the DataFrame look like this:

To get the total number of attacks, we just use the DataFrame's `sum()`

method:

`df["Attacks"].sum()`

**Answer: 212**

To get the years with the most and least vandalism we just use the DataFrame's `max()`

and `min()`

methods:

```
rows_with_most_attacks = df.loc[df['Attacks'] == df["Attacks"].max()]
rows_with_fewest_attacks = df.loc[df['Attacks'] == df["Attacks"].min()]
```

The max is clear. One year, 2024, had 7 attacks, more than in any other year.

**Max: 7 attacks in 2024**

The years with the least number of attacks is slightly more problematic. We code using `min()`

gives us 25 years with only one attack, but there were also years with no attacks at all. We see that by looping through the index of the DataFrame:

```
years_with_no_attacks = []
for year in range(2000,2100):
if year not in df.index:
years_with_no_attacks.append(year)
```

That gives us a list of 21 years with no attacks: 2000, 2037, 2041, 2043, 2047, 2053, 2058, 2059, 2061, 2062, 2067, 2071, 2073, 2074, 2079, 2082, 2083, 2086, 2089, 2094, 2097. Note that if 2058 were a leap year, there would have been an attack on February 29 of that year, but it isn't.

So, I think the answer is:

**Min: 0 attacks in 21 different years**

To figure out the longest gap between two attacks, I went back to the while loop in the setup:

```
longest_gap = timedelta(days=0)
day = date(2001,1,2)
prev_attack = date(2001,1,1)
lastday = date(2099,12,31)
while day <= lastday:
m = day.month
d = day.day
y = day.year - 2000
if m*d == y:
gap = day - prev_attack
if gap > longest_gap:
gap_start = prev_attack
gap_end = day
longest_gap = gap
prev_attack = day
day = day + timedelta(days=1)
print(gap_start, gap_end, longest_gap)
```

This shows us that the longest gap is 1097 days between 03/19/2057 and 03/20/2060. Those were some safe years for famous landmarks.

Notice any mistakes or ideas for improving the code, let me know.

Related Training: Python

About Webucator

Webucator provides instructor-led training to students throughout the US and Canada. We have trained over 90,000 students from over 16,000 organizations on technologies such as Microsoft ASP.NET, Microsoft Office, Azure, Windows, Java, Adobe, Python, SQL, JavaScript, Angular and much more. Check out our complete course catalog.