diff --git a/implement-shell-tools/cat/notes.js b/implement-shell-tools/cat/notes.js new file mode 100644 index 00000000..dc54e635 --- /dev/null +++ b/implement-shell-tools/cat/notes.js @@ -0,0 +1,38 @@ +import process from "node:process"; +import { promises as fs } from "node:fs"; +// const fs = promises + +// * `cat sample-files/1.txt` +// * `cat -n sample-files/1.txt` +// * `cat sample-files/*.txt` +// * `cat -n sample-files/*.txt` +// * `cat -b sample-files/3.txt` + +//from coursework +// const content = await fs.readFile(path, "utf-8"); +// const countOfWordsContainingEs = content +// .split(" ") +// .filter((word) => word.includes("e")) +// .length; +// console.log(countOfWordsContainingEs); + +// process.argv documentation that process.argv[0] will be the path to node +// process.argv[1] will be the path to this file +// the arguments start at index 2 + + + +// 1 `cat sample-files/1.txt` +// async function caseOne(oneFile) { +// const content = await fs.readFile(file, "utf-8"); +// console.log(content); +// } +// 3 `cat sample-files/*.txt` +// async function caseThree(listOfFiles) { +// for (const file of listOfFiles) { +// const content = await fs.readFile(file, "utf-8"); + +// console.log(content); +// } +// } + diff --git a/implement-shell-tools/ls/index.js b/implement-shell-tools/ls/index.js new file mode 100644 index 00000000..c8d962a8 --- /dev/null +++ b/implement-shell-tools/ls/index.js @@ -0,0 +1,50 @@ +// fs.readdir +import process from "node:process"; +import { promises as fs } from "node:fs"; + + +// `ls -1` +async function showAllFilesInDir(directory) { + const listOfFiles = await fs.readdir(directory); + + for (const eachFile of listOfFiles) { + console.log(eachFile); + } +} + +// `ls -1 sample-files` +async function showVisibleInSampleFiles() { + const listOfFiles = await fs.readdir('sample-files'); + + for (const eachFile of listOfFiles) { + if (eachFile[0] !== '.') { + console.log(eachFile); + } + + } +} + + +// `ls -1 -a sample-files` +async function showAllInSampleFiles() { + const listOfFiles = await fs.readdir('sample-files'); + + for (const eachFile of listOfFiles) { + + console.log(eachFile); + + } +} + + + +const argv = process.argv.slice(2); + +if (argv.includes('-a')) { + await showAllInSampleFiles(); +} else if (argv.includes('sample-files')) { + await showVisibleInSampleFiles(); +} else { + await showCurrentDir(); +} + diff --git a/individual-shell-tools/ls/script-02.sh b/individual-shell-tools/ls/script-02.sh index d0a5a10f..9fa05d88 100755 --- a/individual-shell-tools/ls/script-02.sh +++ b/individual-shell-tools/ls/script-02.sh @@ -4,3 +4,4 @@ set -euo pipefail # TODO: Write a command which lists all of the files in the directory named child-directory. # The output should be a list of names: helper-1.txt, helper-2.txt, helper-3.txt. +ls child-directory \ No newline at end of file diff --git a/prep/1.py b/prep/1.py new file mode 100644 index 00000000..0c87a0ef --- /dev/null +++ b/prep/1.py @@ -0,0 +1,10 @@ +# ✍️exercise +# Predict what double("22") will do. Then run the code and check. Did it do what you expected? +# Why did it return the value it did? + +def double(value): + return value * 2 + +#2222 + +print(double("22")) \ No newline at end of file diff --git a/prep/10.py b/prep/10.py new file mode 100644 index 00000000..b7a435bd --- /dev/null +++ b/prep/10.py @@ -0,0 +1,60 @@ +# ✍️exercise +# Try changing the type annotation of Person.preferred_operating_system +# from str to List[str]. + +# Run mypy on the code. + +# It tells us different places that our code is now wrong, because we’re +# passing values of the wrong +# type. + +# We probably also want to rename our field - lists are plural. Rename +# the field to preferred_operating_systems. + +# Run mypy again. + +# Fix all of the places that mypy tells you need changing. Make sure the +# program works as you’d expect. + +from dataclasses import dataclass +from typing import List + +@dataclass(frozen=True) +class Person: + name: str + age: int + preferred_operating_systems: List[str] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: str + + +def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop]: + possible_laptops = [] + for laptop in laptops: + if laptop.operating_system == person.preferred_operating_systems: + possible_laptops.append(laptop) + return possible_laptops + + +people = [ + Person(name="Imran", age=22, preferred_operating_systems=["Ubuntu"]), + Person(name="Eliza", age=34, preferred_operating_systems=["Arch Linux"]), +] + +laptops = [ + Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system="Arch Linux"), + Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system="Ubuntu"), + Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system="ubuntu"), + Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system="macOS"), +] + +for person in people: + possible_laptops = find_possible_laptops(laptops, person) + print(f"Possible laptops for {person.name}: {possible_laptops}") \ No newline at end of file diff --git a/prep/11.py b/prep/11.py new file mode 100644 index 00000000..6a3d9bac --- /dev/null +++ b/prep/11.py @@ -0,0 +1,109 @@ +# exercise +# Write a program which: + +# Already has a list of Laptops that a library has to lend out. +# Accepts user input to create a new Person - it should use the input +# function to read a person’s name, age, and preferred operating system. +# Tells the user how many laptops the library has that have that +# operating system. +# If there is an operating system that has more laptops available, +# tells the user that if they’re willing to accept that operating +# system they’re more likely to get a laptop. +# You should convert the age and preferred operating system input from +# the user into more constrained types as quickly as possible, and +# should output errors to stderr and terminate +# the program with a non-zero exit code if the user input bad values. + +from dataclasses import dataclass +from enum import Enum +from typing import List +from collections import Counter +import sys + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Person: + name: str + age: int + preferred_operating_system: OperatingSystem + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem + +def create_a_new_person() -> Person: + add_name = input("What is your name? \n") + if not add_name or add_name == "" or len(add_name) > 50: + print("Enter a valid name.", file=sys.stderr) + sys.exit(1) + + add_age = int(input("What is your age? \n")) + if add_age < 0 or add_age > 100: + print("Enter a valid age.", file=sys.stderr) + sys.exit(1) + + add_os = input("What is your preferred operating system? \n") + + if add_os not in [os.value for os in OperatingSystem]: + print("Enter a valid operating system.", file=sys.stderr) + sys.exit(1) + + return Person(name=add_name, age=add_age, preferred_operating_system=OperatingSystem(add_os)) + + +def find_possible_laptops(laptops: List[Laptop], person: Person) -> List[Laptop]: + possible_laptops = [] + other_laptops = [] + for laptop in laptops: + if laptop.operating_system == person.preferred_operating_system: + possible_laptops.append(laptop) + else: + other_laptops.append(laptop) + return possible_laptops, other_laptops + +def compare_counts_of_poss_and_others(possible_laptops: List[Laptop], other_laptops: List[Laptop], person: Person) -> None: + # counter to get obj + other_laptops_counted_as_obj = Counter(laptop.operating_system for laptop in other_laptops) + # and here turn to tuple os+count + most_common_laptop = other_laptops_counted_as_obj.most_common(1)[0] + + if len(possible_laptops) < most_common_laptop[1]: + # print(f"There are more laptops available with {str(most_common_laptop[0])} than your preferred OS {person.preferred_operating_system.value}. Consider accepting that OS to increase your chances of getting a laptop.") + print(f"There are more laptops available with {most_common_laptop[0].value} than your preferred OS {person.preferred_operating_system.value}. Consider accepting that OS to increase your chances of getting a laptop.") + else: + print("Your chosen os has the biggest availability.") + +people = [ + # Person(name="Imran", age=22, preferred_operating_system=OperatingSystem.UBUNTU), + # Person(name="Eliza", age=34, preferred_operating_system=OperatingSystem.ARCH), +] + +laptops = [ + Laptop(id=1, manufacturer="Dell", model="XPS", screen_size_in_inches=13, operating_system=OperatingSystem.ARCH), + Laptop(id=2, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU), + Laptop(id=3, manufacturer="Dell", model="XPS", screen_size_in_inches=15, operating_system=OperatingSystem.UBUNTU), + Laptop(id=4, manufacturer="Apple", model="macBook", screen_size_in_inches=13, operating_system=OperatingSystem.MACOS), +] + +for person in people: + possible_laptops = find_possible_laptops(laptops, person) + print(f"Possible laptops for {person.name}: {possible_laptops}") + + +def execute(): + new_person = create_a_new_person() + possible_laptops, other_laptops = find_possible_laptops(laptops, new_person) + print(f"Number of laptops matching your preferred OS: {len(possible_laptops)}") + compare_counts_of_poss_and_others(possible_laptops, other_laptops, new_person) + + +execute() \ No newline at end of file diff --git a/prep/12.py b/prep/12.py new file mode 100644 index 00000000..65584651 --- /dev/null +++ b/prep/12.py @@ -0,0 +1,40 @@ +# Play computer with this code. Predict what you expect each line will do. +# Then run the code and check your predictions. (If any lines cause +# errors, you may need to comment them out to check later lines). + +class Parent: + def __init__(self, first_name: str, last_name: str): + self.first_name = first_name + self.last_name = last_name + + def get_name(self) -> str: + return f"{self.first_name} {self.last_name}" + +class Child(Parent): + def __init__(self, first_name: str, last_name: str): + super().__init__(first_name, last_name) + self.previous_last_names = [] + + def change_last_name(self, last_name) -> None: + self.previous_last_names.append(self.last_name) + self.last_name = last_name + + def get_full_name(self) -> str: + suffix = "" + if len(self.previous_last_names) > 0: + suffix = f" (née {self.previous_last_names[0]})" + return f"{self.first_name} {self.last_name}{suffix}" + +person1 = Child("Elizaveta", "Alekseeva") +print(person1.get_name()) # prints Elizaveta Alekseeva +print(person1.get_full_name()) # prints Elizaveta Alekseeva +person1.change_last_name("Tyurina") # no print +print(person1.get_name()) # prints Elizaveta Tyurina +print(person1.get_full_name()) # prints Elizaveta Tyurina (née Alekseeva) + +person2 = Parent("Elizaveta", "Alekseeva") +print(person2.get_name()) #print Elizaveta Alekseeva +print(person2.get_full_name()) #no full name method +person2.change_last_name("Tyurina") #no change last name method +print(person2.get_name()) # print Elizaveta Alekseeva +print(person2.get_full_name()) #no full name method so err \ No newline at end of file diff --git a/prep/2.py b/prep/2.py new file mode 100644 index 00000000..47f64459 --- /dev/null +++ b/prep/2.py @@ -0,0 +1,10 @@ +# ✍️exercise +# Read the above code and write down what the bug is. +# How would you fix it? + +def double(number): + return number * 3 + +print(double(10)) + +#Either call it tripple or * 2 \ No newline at end of file diff --git a/prep/3.py b/prep/3.py new file mode 100644 index 00000000..177f443f --- /dev/null +++ b/prep/3.py @@ -0,0 +1,43 @@ +# ✍️exercise +# Do not run the following code. + +# This code contains bugs related to types. They are bugs mypy can catch. + +# Read this code to understand what it’s trying to do. +# Add type annotations to the method parameters and return types of this code. +# Run the code through mypy, and fix all of the bugs that show up. +# When you’re confident all of the type annotations are correct, and the bugs are fixed, +# run the code and check it works. + +def open_account(balances, name, amount): + balances[name] = amount + +def sum_balances(accounts): + total = 0 + for name, pence in accounts.items(): + print(f"{name} had balance {pence}") + total += pence + return total + +def format_pence_as_string(total_pence): + if total_pence < 100: + return f"{total_pence}p" + pounds = int(total_pence / 100) + pence = total_pence % 100 + return f"£{pounds}.{pence:02d}" +# File "C:\Users\kkazi\Desktop\cyf\Module-Tools\prep\3.py", line 27, in format_pence_as_string + # return f"£{pounds}.{pence:02d}" + #^^^^^^^^^^^ +#ValueError: Unknown format code 'd' for object of type 'float' +balances = { + "Sima": 700, + "Linn": 545, + "Georg": 831, +} + +open_account(balances, "Tobi", 913) # to solve the float int issue value passed in in pence3.py:35: error: Missing positional argument "amount" in call to "open_account" [call-arg] +open_account(balances, "Olya", 713) #3.py:36: error: Missing positional argument "amount" in call to "open_account" [call-arg] + +total_pence = sum_balances(balances) +total_string = format_pence_as_string(total_pence) # 3.py:39: error: Name "format_pence_as_str" is not defined [name-defined] +print(f"The bank accounts total {total_string}") \ No newline at end of file diff --git a/prep/4-5.py b/prep/4-5.py new file mode 100644 index 00000000..77589bd7 --- /dev/null +++ b/prep/4-5.py @@ -0,0 +1,33 @@ +# Exercise +# Add the is_adult code to the file you saved earlier. + +# Run it through mypy - notice that no errors are reported - mypy understands that Person has a property named age so is happy with the function. + +# Write a new function in the file that accepts a Person as a parameter and tries to access a property that doesn’t exist. +# Run it through mypy and check that it does report an error. + +class Person: + def __init__(self, name: str, age: int, preferred_operating_system: str): + self.name = name + self.age = age + self.preferred_operating_system = preferred_operating_system + +imran = Person("Imran", 22, "Ubuntu") +print(imran.name) +print(imran.address) + +eliza = Person("Eliza", 34, "Arch Linux") +print(eliza.name) +print(eliza.address) + +def is_adult(person: Person) -> bool: + return person.age >= 18 + +print(is_adult(imran)) +#error means prop does not exist + +def get_eye_colour(person: Person): + return person.eye_colour + +print(get_eye_colour(imran)) +#error in mypy no attribute \ No newline at end of file diff --git a/prep/6.py b/prep/6.py new file mode 100644 index 00000000..fb46bf7b --- /dev/null +++ b/prep/6.py @@ -0,0 +1,9 @@ +# exercise +# Think of the advantages of using methods instead of free functions. Write them down in your notebook. +1 makes data and logic more organised +2 makes it easier to find and reuse code +3 makes the code more specific and it is easier to understand what it is doing for + a junior/learner like me :) +4 reduces errors + + diff --git a/prep/7.py b/prep/7.py new file mode 100644 index 00000000..d510ecc9 --- /dev/null +++ b/prep/7.py @@ -0,0 +1,27 @@ +# exercise +# Change the Person class to take a date of birth +# (using the standard library’s datetime.date class) and store it in a +# field instead of age. + +# Update the is_adult method to act the same as before. + +from datetime import date + +class Person: + def __init__(self, name: str, dob: date, preferred_operating_system: str): + self.name = name + self.dob = dob + self.preferred_operating_system = preferred_operating_system + + + def is_adult(self): + today = date.today() + age = date.today().year - self.dob.year + if (today.month, today.day) < (self.dob.month, self.dob.day): + age -= 1 + return age >= 18 + +imran = Person("Imran", date(1988, 10, 10), "Ubuntu") +print(imran.is_adult()) +imran = Person("Jay", date(2015, 10, 10), "Ubuntu") +print(imran.is_adult()) \ No newline at end of file diff --git a/prep/8.py b/prep/8.py new file mode 100644 index 00000000..b7b4c8b3 --- /dev/null +++ b/prep/8.py @@ -0,0 +1,30 @@ +# ✍️exercise +# Write a Person class using @datatype which uses a datetime.date +# for date of birth, rather than an int for age. + +# Re-add the is_adult method to it. + +from dataclasses import dataclass +from datetime import date + +@dataclass +class Person: + # def __init__(self, name: str, dob: date, preferred_operating_system: str): + # self.name = name + # self.dob = dob + # self.preferred_operating_system = preferred_operating_system + name: str + dob: date + preferred_operating_system: str + + def is_adult(self): + today = date.today() + age = date.today().year - self.dob.year + if (today.month, today.day) < (self.dob.month, self.dob.day): + age -= 1 + return age >= 18 + +imran = Person("Imran", date(1988, 10, 10), "Ubuntu") +print(imran.is_adult()) +imran = Person("Jay", date(2015, 10, 10), "Ubuntu") +print(imran.is_adult()) \ No newline at end of file diff --git a/prep/9.py b/prep/9.py new file mode 100644 index 00000000..7afa54ab --- /dev/null +++ b/prep/9.py @@ -0,0 +1,25 @@ +# ✍️exercise +# Fix the above code so that it works. You must not change the print +# on line 17 - we do want to print the children’s ages. +# (Feel free to invent the ages of Imran’s children.) + +from dataclasses import dataclass +from typing import List + +@dataclass(frozen=True) +class Person: + name: str + age: int + children: List["Person"] + +fatma = Person(name="Fatma", age=12, children=[]) +aisha = Person(name="Aisha", age=25, children=[]) + +imran = Person(name="Imran", age=67, children=[fatma, aisha]) + +def print_family_tree(person: Person) -> None: + print(person.name) + for child in person.children: + print(f"- {child.name} ({child.age})") + +print_family_tree(imran) \ No newline at end of file diff --git a/prep/notes.md b/prep/notes.md new file mode 100644 index 00000000..1887d3d5 --- /dev/null +++ b/prep/notes.md @@ -0,0 +1,39 @@ + +def how_many_laptops_match_os(person: Person) -> List[Laptop]: + possible_laptops = [] + for laptop in laptops: + if laptop.operating_system == person.preferred_operating_system: + possible_laptops.append(laptop) + prinet(f"Number of laptops matching your preferred OS: {len(possible_laptops)}") + return possible_laptops + + +# for person in people: +# possible_laptops = find_possible_laptops(laptops, person) +# print(f"Possible laptops for {person.name}: {possible_laptops}") + +# If there is an operating system that has more laptops available, +# tells the user that if they’re willing to accept that operating +# system they’re more likely to get a laptop. + +def get_counts_of_all_laptops_by_os(laptops: List[laptop]) -> dict: + number_of_laptops = {} + + for laptop in laptops: + particular_os = laptop.operating_system + + if particular_os in number_of_laptops: + number_of_laptops[particular_os] += 1 + else: + number_of_laptops[particular_os] = 1 + + return number_of_laptops + +def check_if_there_is_os_with_more_laptops(laptops: List[Laptop], person: Person, possible_laptops: List[Laptop]) -> None: + not_matching_laptop_counts = get_counts_of_all_laptops_by_os(laptops) + + + for laptop in get_counts_of_all_laptops_by_os(laptops): + if laptop.operating_system != person.preferred_operating_system: + not_matching_laptop_counts = get_counts_of_all_laptops_by_os(laptops) + print(f"There are more laptops available with {laptop.operating_system.value} than your preferred OS {person.preferred_operating_system.value}. Consider accepting that OS to increase your chances of getting a laptop.") diff --git a/sprint 5/laptop.py b/sprint 5/laptop.py new file mode 100644 index 00000000..83eb3852 --- /dev/null +++ b/sprint 5/laptop.py @@ -0,0 +1,50 @@ +In the prep, there was an exercise around finding possible laptops for a group of people. + +Your exercise is to extend this to actually allocate laptops to the people. + +Given these class definitions: + +from dataclasses import dataclass +from enum import Enum +from typing import List + +class OperatingSystem(Enum): + MACOS = "macOS" + ARCH = "Arch Linux" + UBUNTU = "Ubuntu" + +@dataclass(frozen=True) +class Person: + name: str + age: int + # Sorted in order of preference, most preferred is first. + preferred_operating_system: List[OperatingSystem] + + +@dataclass(frozen=True) +class Laptop: + id: int + manufacturer: str + model: str + screen_size_in_inches: float + operating_system: OperatingSystem +Write a function with this signature: + +def allocate_laptops(people: List[Person], laptops: List[Laptop]) -> Dict[Person, Laptop]: +Every person should be allocated exactly one laptop. + +If we define "sadness" as the number of places down in someone's ranking the +operating system the ended up with (i.e. if your preferences were [UBUNTU, ARCH, MACOS] + +and you were allocated a MACOS machine your sadness would be 2), we want to minimise the total sadness of +all people. If we allocate someone a laptop with an operating system not in their preferred list, treat +them as having a sadness of 100. + +def ranking(): + + +def minimize_sandess(): + + +def allocate_laptops(): + \ No newline at end of file