<jupyter_start><jupyter_text>SLU18 - Exam preparation II Batch 3 Wave 1This is the 1st Python exam from batch 3. Exam Duration: 3h<jupyter_code>import numpy as np
import pytest
import io
import math
import utils
from math import isclose
import re
import json
import numpy as np<jupyter_output><empty_output><jupyter_text>Exercise 1 Implement a function called **euclidean_distance** that:- Receives two arguments: points x and y. A point is represented as a tuple, for example: (1, 2, 3) or (1.4, -7, 0)- Validates the input arguments:    - Point x must not be None. If it is, raise a ValueError with message "First point must be defined."    - If point y is None, then it defaults to the origin (0,0,...,0) and has as many coordinates as point x    - If the points don’t have the same number of coordinates, raise a ValueError with message "Cannot compute distance between points with different number of coordinates."- Computes the euclidean distance between the two points as: $$d = \sqrt{(x_1 - y_1)^2 + (x_2 - y_2)^2 + ... + (x_n - y_n)^2}$$- Returns the computed distance **Grader tips**In this exercise, you should just define function **euclidean_distance**, and make sure that it has the correct name and takes the correct arguments.You should not invoke the function!<jupyter_code># create function called euclidean_distance

# def euclidean_distance(x, y):
# ...
# ...


# YOUR CODE HERE
raise NotImplementedError()
a = (8, -3, 4)
b = (7, 14, 0)
assert isclose(euclidean_distance(a, b), 17.4928, rel_tol=1e-2) 


a = (1.2, 3, 4.1)
b = (5, 7.8, -9.0)
assert isclose(euclidean_distance(a, b), 14.4599, rel_tol=1e-2)


a = None
b = (1, 2)

with pytest.raises(ValueError) as e:
    euclidean_distance(a, b)
    
assert str(e.value) == 'First point must be defined.'


a = (1, 2, 3)
b = None
assert isclose(euclidean_distance(a, b), 3.7416, rel_tol=1e-2)


a = (8, 9)
b = (1.2, 3, -7, 8)
with pytest.raises(ValueError) as e:
    euclidean_distance(a, b)

msg = 'Cannot compute distance between points with different number of coordinates.'  
assert str(e.value) == msg
    

a = (4, 4, 4)
b = (4, 4, 4)
assert euclidean_distance(a, b) == 0


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>---  Exercise 2 **Indexing words**Implement a function called **create_index** that will index a list of words.This function:- Receives a list called lst as argument. lst will have values with different data types- We don’t care about the values in the list that are not strings- For each string in the list, remove any characters that are not a-z, A-Z- Each non-empty string in the list should be added to a dictionary where    - the keys are the first letter of the words (uppercase)    - the values are lists, where each list has all the words in lst that begin with the letter in the key- The lists that are the dictionary's values should be sorted alphabetically in reversed order- The words in the lists should be lowercase- Return the dictionary **Grader tips**In this exercise, you should just define function **create_index**, and make sure that it has the correct name and takes the correct arguments.You should not invoke the function!<jupyter_code># create function called create_array

# def create_array():
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
lst = ["Salut!", 9, 7.5, [1, 2, 3], "bye", "tomat0", "surpr!se", 13, None]
answer = create_index(lst)
assert answer == {"S": ["surprse", "salut"], "B": ["bye"], "T": ["tomat"]}

lst = []
answer = create_index(lst)
assert answer == {}

lst = ["alice!", '9', 'BOB', None, 'berlim', 'Charlie']
answer = create_index(lst)
assert answer == {"A": ["alice"], "B": ["bob", "berlim"], "C": ["charlie"]}


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>---  Exercise 3 **Parse a JSON file**Define a function called **parse_json**, that parses a file where each line is a json object. The function should behave in the following way:- Receive as argument a **file descriptor** and read through the lines of the file    - Note: a file descriptor is what's returned by the open( ) function when you call it on a file. This means that, given the argument that the function parse_json receives is already a file descriptor, you don't need to open the file anymore!- If you can’t convert a line into a python dictionary, ignore that line and move on to the next one- Each dictionary should have at least two keys: A and B. Discard the lines that don’t have these two keys (i.e, the dictionaries must have both key A and key B)- Get the smallest number from all the values with key A. Discard any non int/float values with key A- Get the longest string from all the values with key B. Discard any non string values with key B- Return a list like **[smallest_number_in_A, longest_string_in_B]**- In case there is more than one candidate for longest_string_in_B, return the one that showed up first in the file- If there is no smallest_number_in_A or longest_string_in_B, use None in the list instead (e.g, return [None, 'bla'] or [-2, None])<jupyter_code># create function called parse_json

#def parse_json(f):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
data = (
    '{"C": 3}\n'
    '{"A": 1, "B": "Hello"}\n'
    '"Blabla"\n'
    '{"C": 76, "A": -14, "B": 7}\n'
    '{"C": "Bla", "D": 34, "B": "This is a string!"}\n'
    '{"B":"A", "A": 50.5}'
)

fd = io.StringIO(data)
assert parse_json(fd) == [-14, 'Hello']

data = (
    '{"C": 3}\n'
    '{"A": "1", "B": "Hello"}\n'
    '"Blabla"'
)
fd = io.StringIO(data)
assert parse_json(fd) == [None, 'Hello']

data = (
    '{"C": 3}\n'
    '{"A": "1", "B": 3}\n'
    '"Blabla"'
)
fd = io.StringIO(data)
assert parse_json(fd) == [None, None]
    

print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>---  Exercise 4  Linked List**1.4. Defining Node**The following exercises will be about a data structure called **linked list.**A linked list is a sequence of nodes. These nodes that can hold a certain value, and have a link that points to the next element in the list.**Attention: In this exercise we will sometimes refer to "linked lists" as just "lists". This doesn't mean that you should use Python lists to implement the linked list data structure. In fact, you will probably solve Exercise 4 without using a single Python list!** In this first exercise, you'll implement a class called **Node**. Node has 2 instance variables, that are passed into the constructor (to be initialized) in the following order:- *value*: it can be of any data type. By default it should be None- *next_node*: this is the link that points to the next element in the linked list. By default it points to NoneAs an illustration, this is a **Node**: **Grader tips**To test your class we're going to check the following:- try to instantiate it with the values you see on the Sample Input (first value is value, second value is next_node)- check if it has two instance variables (value and next_node)- check if the instance variables have the values passed in the inputYou just need to implement the class, you don't need to do anything else.<jupyter_code># create class called Node

# class Node:
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
node = Node(1, 'next')
assert isinstance(node, Node)
assert hasattr(node, 'value') and hasattr(node, 'next_node')
assert node.value == 1
assert node.next_node == 'next'

node = Node()
assert isinstance(node, Node)
assert hasattr(node, 'value') and hasattr(node, 'next_node')
assert node.value is None
assert node.next_node is None


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**4.2. Defining LinkedList**In this second exercise, you will implement another class called **LinkedList**:- It has one instance variable of type Node, called base. The base node is considered the zero-node in the list: its value is None, its next_node points to the first node in the list, it can never be removed and doesn’t count as a list node. This is an example of an empty list, just with a base. - It has one method called add_node, that:    - Receives an argument called value. If value is None, just return without doing anything else    - Adds a new Node to the end of the list, with the value specified in value    - Doesn’t return anything- It has one method called remove_node, that:    - Receives an argument called value. If value is None, just return without doing anything else    - Finds the first node in the list with that value and removes it from the list    - If there are no nodes in the list with that value, the list should remain unchanged    - Doesn't return anything- It has one method called count_nodes, that:    - Doesn’t receive any argument    - Counts the number of nodes in the list and returns it    - The base node should not be included in the countExamples:This is a linked list after method add_node was called 4 times, with values 10, 3, 7 and 9, respectively.This is the previous list after method remove_node was called once, with value 7.This is the previous list after method remove_node was called once, with value 10. Be careful when removing the first node from the list! **Grader tips**For this exercise, you can assume that there is already an implementation of class Node, and that you can instantiate it by calling Node(). So, even if you didn't complete the previous exercise, you can still solve this one.You just need to implement the class, you don't need to do anything else!<jupyter_code># create function called create_array

# def add_node(self, value):
# ...
# def remove_node(self, value):
# ...
# def count_nodes(self):
# ...

# YOUR CODE HERE
raise NotImplementedError()

def count_nodes(l):
    n_nodes = 0
    p = l.base
    while p.next_node is not None:
        p = p.next_node
        n_nodes += 1
    return n_nodes


ll = LinkedList()
assert isinstance(ll, LinkedList)
assert hasattr(ll, 'base')
assert isinstance(ll.base, Node)
assert ll.base.value is None
assert ll.base.next_node is None


ll = LinkedList()
ll.add_node(3)

# list: 3

nodes_before = count_nodes(ll)
ll.add_node(None)

# list: 3 None
nodes_after = count_nodes(ll)
assert nodes_before == nodes_after

first_node = ll.base.next_node
assert first_node.value == 3
assert first_node.next_node is None

ll = LinkedList()
ll.add_node(3)
# list: 3 None 3
assert ll.base.next_node is not None
assert ll.base.next_node.value == 3


ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')



# list: 3 'hello'
first_node = ll.base.next_node
second_node = first_node.next_node
assert first_node.value == 3
assert first_node.next_node is not None
assert second_node.value == 'hello'
assert second_node.next_node is None


ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')
ll.add_node(4)
ll.add_node(5)
ll.add_node(6)


# list: 3 'hello' 4 5 6
nodes_before = count_nodes(ll)
ll.remove_node(6)
nodes_after = count_nodes(ll)

assert nodes_after == nodes_before - 1
    

last = ll.base
while last.next_node is not None:
    last = last.next_node

assert last.value == 5


ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')
ll.add_node(4)
ll.add_node(5)


# list: 3 'hello' 4 5

nodes_before = count_nodes(ll)
ll.remove_node(4)
nodes_after = count_nodes(ll)
assert nodes_after == nodes_before - 1

p = ll.base.next_node
assert p.value == 3

p = p.next_node
assert p.value == 'hello'

p = p.next_node
assert p.value == 5
assert p.next_node is None


print("Answer is correct. Good Job.")

ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')
ll.add_node(5)


# list: 3 'hello' 5

nodes_before = count_nodes(ll)
ll.remove_node(3)
nodes_after = count_nodes(ll)
assert nodes_after == nodes_before - 1

p = ll.base.next_node
assert p.value == 'hello'

p = p.next_node
assert p.value == 5
assert p.next_node is None


ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')
ll.add_node(5)



# list: 3 'hello' 5

nodes_before = count_nodes(ll)
ll.remove_node(None)
nodes_after = count_nodes(ll)
assert nodes_before == nodes_after


ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')
ll.add_node(5)


# list: 3 'hello' 5

nodes_before = count_nodes(ll)
ll.remove_node(4)
nodes_after = count_nodes(ll)
assert nodes_before == nodes_after


ll = LinkedList()
ll.add_node(3)
ll.add_node('hello')
ll.add_node(5)
ll.add_node(5)


# list: 3 'hello' 5 5

nodes_before = count_nodes(ll)
ll.remove_node(5)
nodes_after = count_nodes(ll)
assert nodes_after == nodes_before - 1
    

ll = LinkedList()
ll.add_node('hello')
ll.add_node(5)

# list: 'hello' 5
assert ll.count_nodes() == 2

ll = LinkedList()
assert ll.count_nodes() == 0


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**4.3. Playing with linked lists** On the following exercises, we'll play with linked lists!Now, you should create a function called **create_list**, that doesn't receive any arguments and that returns an instance of class LinkedList exactly like this one.<jupyter_code># create function called create_list

# def create_list():
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
l = create_list()
assert isinstance(l, LinkedList)
assert isinstance(l.base, Node)
assert l.base.value is None
assert l.base.next_node is not None
assert l.count_nodes() == 4

p = l.base.next_node
assert p.value == 10

p = p.next_node
assert p.value == 3

p = p.next_node
assert p.value == 7

p = p.next_node
assert p.value == 9

p = p.next_node
assert p is None


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**4.4. Playing with linked lists**Now, you should create a function called **update_list**, that receives this linked list as argument (the one that we built in the last exercise):And then returns this one: **Grader tips**For this exercise, you can assume that class **LinkedList** is already implemented, with all the methods described in the previous exercises. So, even if you didn't complete the previous exercises, you can still solve this one.You just need to implement the function, you should not invoke it!<jupyter_code># create function called update_list

# def update_list(l):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()

l = LinkedList()
l.add_node(10)
l.add_node(3)
l.add_node(7)
l.add_node(9)


# List: base -> 10 -> 3 -> 7 -> 9
l = update_list(l)
# List: base -> 3 -> 9

assert isinstance(l, LinkedList)
assert isinstance(l.base, Node)
assert l.base.value is None
assert l.base.next_node is not None
assert l.count_nodes() == 2

p = l.base.next_node
assert p.value == 3

p = p.next_node
assert p.value == 9

p = p.next_node
assert p is None


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>---  Exercise 5 **5.1 - Gimme ones**Write a function called **gimme_ones** that takes an argument n and returns a numpy array with shape (n,) where all the values are ones.**Examples:**- **Input:** 4        **Output:** array([1., 1., 1., 1.])    - **Input:** 1        **Output:** array([1.])<jupyter_code># create function called gimme_ones

# def gimme_ones(n):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()


assert np.array_equal(gimme_ones(3), np.ones(3))
assert np.array_equal(gimme_ones(1), np.ones(1))


print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**5.2 - Gimme numbers**Now write a function called **gimme_numbers** that:- receives two positional arguments: n and x- calls function gimme_ones with n- multiplies the ones by x- returns the resulting numpy array<jupyter_code># create function called gimme_numbers

# def gimme_numbers(n,x):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()


assert np.array_equal(gimme_numbers(3, 5.67), np.ones(3) * 5.67)
print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>---  Exercise 6 - Numpy **6.1 - Creating arrays**Consider this matrix.   $$        \begin{bmatrix}            1 & 2 & 3\\            4 & 5 & 6\\            7 & 8 & 9        \end{bmatrix}\;\;    $$ Implement a function call **create_array** that creates a numpy array with the data in the matrix above, and returns it.<jupyter_code># create function called create_array

# def create_array():
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
assert np.array_equal(create_array(), np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**6.2 - Subsetting arrays**Implement a function called **select_first_col**, that receives a numpy array and returns it's first column.You don't need to do any validations on the input array shape.If you consider as input the array that you created in the previous question, then the output should have shape (3,).<jupyter_code># create function called select_first_col

# def select_first_col(q):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()

a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
assert np.array_equal(select_first_col(a), a[:, 0])
print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**6.3 - Selecting values arrays**Implement a function called **select_values**, that receives a numpy array and returns all the values in the array that are **bigger than 4**.If you consider as input the array that you created in the first question, then the shape of the return value should be (5,).<jupyter_code># create function called select_values

# def select_values(x):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
assert np.array_equal(select_values(a), a[a > 4])
print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>**6.4 - Invert values**Implement a function called **invert_values**, that:- receives a numpy array- checks if there are any 0 in the array. If yes return False- otherwise, returns an array with the same shape as the input, where all the values are 1/value<jupyter_code># create function called invert_values

# def invert_values(x):
# ...
# ...

# YOUR CODE HERE
raise NotImplementedError()
a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
assert np.array_equal(invert_values(a), 1 / a)

a = np.array([[1, 2, 3], [4, 0, 6], [7, 8, 9]])
assert not invert_values(a)
print("Answer is correct. Good Job.")<jupyter_output><empty_output><jupyter_text>Exercise 7 - Git questions This exercise is a quiz with 5 multiple answer questions.In the cell below, we've declared a dictionary called `answers`.You should fill in that dictionary with your answers, using as keys the question number, like `question_x`, and as values the number from `1` to `4` that corresponds to the right answer.For each question, you should provide only one answer, i.e, the dict values should have type **int**.For example, if you want to answer Question 1 with choice number 2, then you do:```answers["question_1"] = 2```<jupyter_code>answers = {}<jupyter_output><empty_output><jupyter_text>**Question 1** You just found a cool Git repository on GitHub and you want to have it on your local machine.Which command will you use?1. git clone2. git push3. git add4. git pull<jupyter_code># answers["question_1"] = ...

# YOUR CODE HERE
raise NotImplementedError()<jupyter_output><empty_output><jupyter_text>**Question 2** On your local machine, you’re tracking a remote repository. You know that people have made some changes to the code in that repo and now you want to have these new changes in your local machine too.In general, what should you do?1. git clone2. git pull3. git push4. git add<jupyter_code># answers["question_2"] = ...

# YOUR CODE HERE
raise NotImplementedError()<jupyter_output><empty_output><jupyter_text>**Question 3** You’ve been working on your local machine on some files, and now you’re happy about the changes you’ve made.What’s the first thing that you need to do, for Git to start tracking the changes you’ve made to the files locally?1. git commit2. git stash3. git push4. git add<jupyter_code># answers["question_3"] = ...

# YOUR CODE HERE
raise NotImplementedError()<jupyter_output><empty_output><jupyter_text>**Question 4** What if you’re working on some files but now you need to run a script without your local changes? So, you just want to go back to the original version of the files for a while, and then return and keep working on your changes to the files.1. git add2. git stash3. git push4. git commit<jupyter_code># answers["question_4"] = ...

# YOUR CODE HERE
raise NotImplementedError()<jupyter_output><empty_output><jupyter_text>**Question 5** What do you need to do next, so that your changes are recorded?1. git stash2. git push3. git add4. git commit<jupyter_code># answers["question_5"] = ...

# YOUR CODE HERE
raise NotImplementedError()
# Run this cell to see if your answers are correct

utils.exercise_7(answers)<jupyter_output><empty_output><jupyter_text>---  Last but not least, submit your work! To submit your work, fill your slack ID in the `slack_id` variable (as a string).Example: `slack_id = "x-men"`Help: if you forgot your slack ID, [read this](https://moshfeu.medium.com/how-to-find-my-member-id-in-slack-workspace-d4bba942e38c).<jupyter_code># Submit your work!

#slack_id = 

# YOUR CODE HERE
raise NotImplementedError()
from submit import submit
assert isinstance(slack_id, str)

slu = 18_1
submit(slack_id, slu)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1119549929676512, 'fraction_numerical': 0.01706516643225504, 'mean_word_length': 4.37440161249685, 'pattern_counts': {'":': 23, '<': 85, '<?xml version=': 0, '>': 92, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '467179', 'license': 'MIT', 'n_tokens_mistral': 7076, 'n_tokens_neox': 6702, 'n_words': 2760, 'path': 'Week 11/SLU18_1 - Exam Prep II/Exercise notebook.ipynb', 'repo_name': 'LDSSA/ds-prep-course-2021', 'size': '21330'}