# Initializing a Tuple
day_tuple = ("MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")

"""
Explanation: Tuples
A tuple is an immutable, indexable, and heterogenous sequence of objects. Unlike a list, the immutability of tuple bars it from being able to change its objects (in place). The semantics of the tuple allow us to use it as a data structure that holds constant values. In this lecture, we will cover:
1. Initializing a Tuple
2. Accessing, Slicing, and Modifying a Tuple
3. Tuple Functions and Methods

Let us begin by initializing a tuple. 
Initializing a Tuple
Unlike a list, a tuples objects is physically bounded by parentheses. Tuples can be heterogenous, as lists are too.
End of explanation
"""


# Initializing a heterogenous Tuple
my_tuple = ("red", 40, 9.0, [1, 4, 5], "hey", {"Micah":9})

"""
Explanation: Here is an example of a heterogenous tuple. Recall that are definable types in Python are objects, and thus even data structures like lists and dictionaries can be the items of a tuple. On the flipside, tuples can act as a key and a value in a dictionary! This is because all keys in a dictionary must be hashable, and tuples are. Tuples can also be objects in lists.
End of explanation
"""


# Initializing a Tuple
day_tuple = ("MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")
# Access Thursday
print(day_tuple[3])

"""
Explanation: Tuple Access, Slicing, and Modification
You can access any item in a tuple with bracket notation.
End of explanation
"""


# Getting all of the items in a tuple using slicing
print(day_tuple[0:])

"""
Explanation: Because tuples and lists are sequences, we cannot search by some "key". Only mappings can perform actions like these naturally (we have a way to do this, in the methods section). A tuple semantically acts the same as a list, and as you are already familiar with a list, can perform slicing.
End of explanation
"""


# Getting every other object in a Tuple
print(day_tuple[::2])

# Getting the tuple objects backward
print(day_tuple[::-1])

"""
Explanation: All structures that can use slicing (sequences... i.e. strings, tuples, lists) have skips. Recall the general notation for slicing.
my_sequence[start:end:skip]

where "start" is inclusive, end is exclusive, and skip is the sequence traversal factor.
End of explanation
"""


# Intializing a Tuple
day_tuple = ("MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")
# Attempt to change an item via access bracket notation
day_tuple[1] = "SUNDAY"

"""
Explanation: Now that we've seen accessing by normal bracket notation and slicing, let's discuss modification. Tuples are immutable sequences, meaning that they cannot be changed in place. What does this mean exactly? Like strings, tuples can physically change what they are referring to but they cannot change the obejcts that are in them in place.
End of explanation
"""


# Intializing a Tuple
day_tuple = ("MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")
# Changing the Tuple object instead of modifying the current
day_tuple = ("MONDAY", "SUNDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")
# Verify that Tuesday is now Sunday
print(day_tuple)

"""
Explanation: While immutability stops us from modifying the object we are currently pointing to (the tuple literal), we can simply just refer to another tuple object.
End of explanation
"""


len(day_tuple)

"""
Explanation: No form of modification on an already existing tuple object will work, whether is appending, prepending, etc. Only reassignment.
Tuple Functions and Methods
There are a few functions and methods associated with tuples. We explore them below.
Tuple Functions
As always, we know that the len() function works on tuples.
End of explanation
"""


# Initializing the Tuple
day_tuple = ("MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")
# Counting how many Mondays there are
day_tuple.count("MONDAY")
# Reassigning the object to have more Mondays
day_tuple = ("MONDAY", "WEDNESDAY", "MONDAY", "THURSDAY", "FRIDAY")
# Recounting the number of Mondays
day_tuple.count("MONDAY")

"""
Explanation: Tuple Methods
The two primary methods we should be aware of that tuples posses are count() and index().
Calling the count(object) method on a tuple returns the number of occurences of the explicit object in the tuple.
End of explanation
"""


# Initializing a Tuple (with ony one WEDNESDAY string literal)
day_tuple = ("MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY")
# Return the index of Wednesday
day_tuple.index("WEDNESDAY")
# Reassign the tuple to another object
day_tuple = ("WEDNESDAY", "TUESDAY", "WEDNESDAY", "FRIDAY", "WEDNESAY")
# What index will it return now that are 3 "WEDNESDAY" string literals
day_tuple.index("WEDNESDAY")

"""
Explanation: The index(object) methods finds the first occurence of the explicit object, and returns the indice.
End of explanation
"""


