---
# System prepended metadata

title: ACIT 1515 - Lesson 9
tags: [ACIT-1515]

---

<style>
    .markdown-body h1:first-of-type {
        margin-top: 24px;
    }
    .markdown-body h1 {
        margin-top: 64px;
    }
    .markdown-body h1 + h2 {
        margin-top: 32px;
    }
    .markdown-body h2 {
        margin-top: 48px;
    }
    .markdown-body h2.topics {
        font-size: 1.8em;
        border-bottom: none;
    }
    .markdown-body h3 {
        color: cornflowerblue;
    }
    .markdown-body h4 {
        color: cornflowerblue;
    }
    .markdown-body p strong {
    }
    .exercise {
        font-size: 150%;
        font-weight: bold;
        color: rgb(227,112,183);
    }
    .note {
        color: red;
    }
    ul ul ::marker {
        content: '- ';
    }
</style>

# ACIT 1515 - Lesson 9

<h2 class="topics">Topics</h2>

- [Sets](#Sets)
- [String Methods](#String-Methods)


## Sets

Sets, like sequences and dictionaries, allow us to store multiple values in a single variable, however sets are _unordered_ and (most importantly) **do not allow duplicate values**.

Sets are declared using curly braces:

```python=
grades = { 80, 75, 90, 90 }
```

As they are considered _unordered_, square bracket syntax is not allowed. This means that we cannot read values by index (position) in the set, we can only test if a value is _in_ a set or not.

```python=
grades = { 80, 75, 90, 90 }

print(grades[0]) 
# TypeError! 'set' object is not subscriptable
# n.b.: 'subscriptable' refers to the use of square brackets

print(80 in grades) # prints True
```

Although sets are **not** sequences, and do not allow most of the sequence operations noted in [Lesson 5](https://hackmd.io/@charris17/acit1515-lesson5#Sequence-Operations), we _can_ get the length of a set using the `len()` function.

Duplicate values are not allowed in a set, and are thus discarded if they exist. Our original `grades` variable above had a duplicate value (the number 90), so testing the length returns 3, not 4!

```python=
grades = { 80, 75, 90, 90 }

print(len(grades)) # prints 3, the second 90 value is discarded
```

Sets, however, are _mutable_. We **cannot** use sequence operations like indexing or slicing to reassign values in the set, but we can `add()` or `remove()` values.

```python=
grades = { 80, 75, 90, 90 }
print(grades) # prints { 80, 90, 75 }

grades.add(80) # duplicate value, ignored
print(grades) # prints { 80, 90, 75 }

grades.remove(80)
print(grades) # prints { 90, 75 }
```

### Empty Sets

If, for any reason, we need to create an _empty_ set, we cannot use the following code:

```python=
empty_set = {}
```

The value above is not a set! Printing the type returns the following:

```python=
empty_set = {}
print(type(empty_set)) # prints <class 'dict'>
```

`empty_set` is a dictionary!. If we do need to create an empty set, we can use the `set()` method:

```python=
empty_set = set()
print(type(empty_set)) # prints <class 'set'>
```

### Set Methods

In addition to the `add` and `remove` methods noted above, sets in Python support typical mathematical set operations, like `union`, `intersection`, and `difference`. These methods can be useful in ways that you might not expect:

```python=
# Find the characters that are common to two strings
a = set('python')
b = set('javascript')
common = a.intersection(b)
print(common) # { p, t } 
```

## String Methods

Below is an inexhaustive list of string methods, allowing you to create modified copies of strings:

`string.strip()` - strip whitespace from a string

```python=
name = ' Chris '
print(len(name)) # prints 7 (Chris + two space characters)
name = name.strip()
print(len(name)) # prints 5, leading and trailing spaces removed
```

`string.split()` - turn a string into a list. The string is split by default at space characters, or can be split on an argument you provide

```python=
name = 'Akila Ramani'
print(name.split()) # prints ['Akila', 'Ramani'], split on space

grades = '80,75,90,78'
print(grades.split(',')) # prints ['80', '75', '90', '78']
```

`string.lower()` - lowercase a string

```python=
name = 'Tom Lane'
print(name.lower()) # prints 'tom lane'
```

`string.upper()` - uppercase a string
```python=
name = 'Tom Lane'
print(name.upper()) # prints 'TOM LANE'
```

`string.capitalize()` - capitalize a string

```python=
name = 'tom lane'
print(name.capitalize()) # prints 'Tom lane'
```

`string.title()` - title-case a string

```python=
name = 'tom lane'
print(name.title()) # prints 'Tom Lane'
```

`string.replace()` - replace a character in a string with another character

```python=
name = 'Tom,Lane'
name = name.replace(',', ' ') # replace commas with spaces
print(name) # prints 'Tom Lane'
```

<!--
- [Review: The Building Blocks of Python](#Review-The-Building-Blocks-of-Python)
- [Problem Solving: Strategies for Writing Programs](Problem-Solving-Strategies-for-Writing-Programs)

### Review: The Building Blocks of Python

#### Variables and Data Types

```python=
name = 'Ed'    # string - any value between quotation marks, immutable
age = 12       # integer
mark = 85.5    # float
courses = []   # empty list - mutable, ordered
x = (1, 2)     # tuple - immutable
y = set()      # empty set - mutable, unordered, unique values only
z = {}         # empty dictionary, contains key/value pairs
dog = {        # dictionary
    "name": "Charlie",
    "age": 12
}

# Get the data type of a value or variable
print(type(10)) # <class 'int'>   
print(type(dog)) # <class 'dict'>
```

#### Basic Operators

```
Arithmetic
+, -, *, /, %, ** 

Assignment
=

Comparison
==, !=, >, <, >=, <=

Logical 
and, or, not
```

#### Loops

```python=
# For loop with range, use when a number or position is required
for i in range(10):
    print(i)
    
for i in range(len(name)):
    print(i, name[i])
    
# For loop with sequence, use when a value is required and position is not
for val in x:
    print(val)    # 1, 2
    
for val in name:
    print(val)    # 'E', 'd'
    
# For loop with dictionary
for k in d.keys():
    print(k) # prints keys
    
for v in d.values():
    print(v) # prints values
    
for k, v in d.items():
    print(k, v) # prints keys and values
    
# While loop
while True:
    # infinite loop until
    break
    
while value > 0:
    print(value)
    value -= 1
```

#### Conditional statements, in operator

```python=
# Comparison
if value > 10:
    print('greater than ten')

# Testing boolean value
if isWeekend:
    print('Relax')
    
# Testing multiple conditions using and/or
if isWeekend and tired:
    print('Relax')
    
if isWeekday or not tired:
    print('Work')
    
# Testing whether value is in a sequence
if 5 in numbers:
    print('The list contains the number 5')
    
# Testing whether value is a set
if 5 in number_set:
    print('The set contains the number 5')
    
# Testing whether key exists in dictionary
if name in student:
    print('Student contains the key "name"')
```

#### Functions

```python=
# Declare a function with no arguments
def f():
    print('Inside the function')
    
# Calling/running/executing/invoking the function
f()

# Declare a function with parameters:
def g(p, q):
    print(p, q)
    
# Calling function and passing arguments:
g(10, 20)

# Define default arguments for function parameters
def h(a, b = 20):
    print(a + b)

# Calling function with default parameter arguments
h(10, 30) # prints 40, a = 10, b = 30
h(10) # prints 30, a = 10, b = 20

# Ending function with the return keyword
def j(a, b):
    if type(a) != type(b):
        return
    print(a + b)
    
# Returning a value from a function using the return keyword
def k(a, b)
    if type(a) != type(b):
        return 
    return a + b

# Using the value returned from a function
result = k(10, 20)
print(result)
```

#### File operations

```python=
# Opening a file for reading
with open('test.txt', 'r') as file:
    # ...
    
# Opening a file for writing
with open('test.txt', 'w') as file:
    # ...
    
# Writing dictionaries/lists to JSON
with open('test.json', 'w') as file:
    json.dump(data, file)
    
# Reading objects/lists from JSON
with open('test.json', 'r') as file:
    data = json.load(file)
```

#### Exceptions

```python=
# Catch any runtime error
try:
    # code that may throw an exception
except:
    # handle the error and prevent the crash
    
# Catch any runtime error and print the interpreter's error message
try:
    # code that may throw an exception
except Exception as e:
    print(e) # prevent crash, print error message
    
# Catching specific error types
try:
    # code that may throw an exception
except ValueError:
    print('ValueError exception occurred')
except (FileNotFoundError, JSONDecodeError):
    print('Valid data not found')
except KeyError as e:
    print('KeyError exception:', e)
```

### Problem Solving: Strategies for Writing Programs

When presented with a new programming challenge:

* **Anticipate**: Take time before coding to try and define the problem for yourself, breaking it down into manageable pieces whenever possible. Ask yourself:
    * What parts are familiar?
    * What are the steps necessary to start and solve the problem?
    * What are the inputs (user input? files? network request?) and outputs
    * Once you think you have the basic idea in mind, challenge your assumptions - does your step-by-step plan cover all the edge cases and errors that may occur?

* **Translate**: Translate your ideas into data structures and programming constructs
    * What variables need to be created?
    * What data types should be used to represent information? Lists, sets, dictionaries?
    * Are functions, loops, or conditional statements required? 

* **Iterate**: Write code, small pieces at a time, testing and debugging often. As you proceed through the program you will naturally encounter problems that you did not anticipate. When that happens, don't be afraid to go back to the first step and start the process again. 
-->