A document from MCS 275 Spring 2024, instructor Emily Dumas. You can also get the notebook file.

MCS 275 Spring 2024 Worksheet 13 Solutions

  • Course instructor: Emily Dumas
  • Contributors to this document: Karoline Dubin, Emily Dumas, Johnny Joyce, Kylash Viswanathan

Topics

This worksheet focuses on Flask web applications, anonymous functions, and decorators.

1. Get TaskGain or ActiveTask running locally

(Setup description omitted; problem heading preserved to make it clear problem 2 refers to this application.)

2. New features

Modify the sample application to add these new features. Test them to make sure they work.

A. Single task view

Make a new route /task/<taskid>/ that does the following:

  • Performs a DB query to get data about the task with id taskid
  • If this query fails, returns a 400 Bad Request error
  • If the query succeeds, it renders a template called task_view.html that you create in the templates/ subdirectory which displays a page listing all the information about that task in a nice format (e.g. with labels for the different fields and proper formatting for the dates/times)
  • In that page, any time a username is displayed, it is actually a link to that user's task list view.

Then, modify the /task/new/submit route so that when a new task is created, the redirect goes to the single task view page for the newly-created task. To do this, you'll need to know this neat trick: The query

SELECT last_insert_rowid();

will return the primary key of the most recently inserted row. So calling this immediately after an SQL INSERT is the proper way to find the unique identifier of the added row.

B. On this day

Here's a function that can take a day described by its year, month, and day numbers and return two time stamps ts0,ts1 so that a timestamp x lies within that day if and only if ts0 <= x < ts1.

In [ ]:
import datetime

def timestamp_range_for_day(year,month,day):
    """
    Return the timestamps when a calendar day
    begins and ends.
    """
    ts0 = datetime.datetime(year,month,day).timestamp()
    ts1 = (datetime.datetime(year,month,day)+datetime.timedelta(days=1)).timestamp()
    return ts0,ts1

Use this to add the following feature to the task list management application: Visiting a URL of the form /reports/day/2024/04/09/ will show a page with two sections:

  • Tasks created on that day
  • Tasks that were last updated on that day

Each section should contain a list of tasks with the described property.

As with the previous feature, this one should use a new template. It is recommended to base your work on the task list view template, since that one also involves a task list.

Solution

It would be quite difficult to place all of the solutions in cells in this notebook. Instead, the following links can be used to download full versions of the apps that include all of the changes we need to make:

The changes are as follows:

  • A new template single_task_view.html was added
  • A new template on_this_day.html was added
  • The provided function timestamp_range_for_day() was added to the main python script
  • A new function single_task_view that handles /task/<int:taskid>/ was added to the main python script
  • A new function on_this_day that handles /reports/day/<int:year>/<int:month>/<int:day>/ was added to the main python script
  • The function add_task was modified to get the created taskid and redirect to the single task view page

Also, the version of the app provided here had one additional convenience feature:

  • The front page has a link to the new task form.

3. Custom sorts and max/min

Use anonymous functions (lambda) with Python's sorted(), max(), or min() functions to answer these questions.

A.

Generate the first 20 powers of 7 (meaning $7^1$ to $7^{20}$) and sort them according to how many different decimal digits they use. That is, 343 would appear near the start of the list since it uses only two distinct digits, while 1628413597910449 would appear near the end, as it uses all 10 digits.

Solution

In [4]:
sorted([7**x for x in range(1,21)], key = lambda x: len(set(str(x))))
Out[4]:
[7,
 49,
 343,
 2401,
 16807,
 117649,
 823543,
 40353607,
 282475249,
 79792266297612001,
 5764801,
 1977326743,
 13841287201,
 96889010407,
 33232930569601,
 11398895185373143,
 678223072849,
 4747561509943,
 232630513987207,
 1628413597910449]

B.

Here's a text file with 10000 English words, one per line:

Let's say the endscore of a word is the number of times its last letter appears in the word. For example, "plasma" has an endscore of 2 because the last letter, a, appears twice. And "associates" has an endscope of 3 because it contains 3 copies of the last letter, s.

Using custom sorting and lambda, find 20 words with the highest endscores in this list.

Solution

We can use the following cell to open the list of words:

In [6]:
words = [x.strip() for x in open("wordlist.10000.txt","rt").readlines()]

Then the following lambda function counts the number of occurrences of the final letter: lambda w: w.count(w[-1])).

This results in the following answer:

In [7]:
sorted(words, key = lambda w: w.count(w[-1]))[-20:]
Out[7]:
['evanescence',
 'everywhere',
 'excellence',
 'experience',
 'independence',
 'interference',
 'massachusetts',
 'mississippi',
 'possess',
 'preference',
 'reference',
 'refrigerator',
 'representative',
 'sessions',
 'submissions',
 'sunglasses',
 'tennessee',
 'volleyball',
 'assessments',
 'documentcreatetextnode']

C.

Use the same word list as the last problem. Suppose we say the variety of a word is the ratio of the number of distinct letters to the length of the word. For example, "cameras" has 6 distinct letters and has a length of 7, so its variety is $\frac67 \approx 0.85714$.

Among words with at least four letters, find one that has the lowest variety.

Solution:

To find the variety of a word w, we can use len(set(w))/len(w). So the answer is as follows:

In [8]:
sorted([ w for w in words if len(w)>=4], key = lambda w: len(set(w))/len(w))[:10]
Out[8]:
['mississippi',
 'barbara',
 'tennessee',
 'engineering',
 'anna',
 'annotation',
 'assess',
 'assessed',
 'banana',
 'boob']

To verify that this formula works, let's find the position of the word "cameras" in the list:

In [9]:
idx = words.index("cameras")
print(idx)
1300

Then the cell below shows us that the variety is approximately 0.85714, as expected

In [11]:
print("The word {} has variety {}".format(words[idx], len(set(words[idx]))/len(words[idx])))
The word cameras has variety 0.8571428571428571

Revision history

  • 2024-04-14 Initial release