<jupyter_start><jupyter_text>Basic OperationsThis notebook is by no means a substitute for any of the excellent educational resources available online, which do a far better job of introducing the fundamentals of Python. The goal is not to cover even scratch the surface of what Python is capable of doing, but to merely highlight some aspects of Python that you will see frequently in this class.To summarize, the objectives of this notebook are to:1. Explain some common code snippetts frequently used in numerical programs.2. Some pitfalls, tips, and tricks when working with and debugging numerical programs.   Lists Lists are a very common data structure, and they are data structures do exactly like what they sound like they do - store separate data entries in a list. For instance, the following is a list of strings,```my_todo_list = ["do homework", "read", "clean the kitchen"]```We can also store a list of numbers. For instance, a list of homework grades, ```my_grades = [90, 80, 100]```However, for numerical programs we will only occassionally use the list data structure. They are convenient and useful, but they are not the most efficient data structures for our numerical calculations. Instead we will use `NumPy` arrays, which will be introduced later. First, though, a brief introduction to lists and list comprehensions.<jupyter_code>my_grades = [90, 80, 100]
print(f'A list of my homework grades: {my_grades}')
# Add a new grade to the list
my_grades.append(75)
print(f'A list of my homework grades: {my_grades}')
print(f'Total number of grades: {len(my_grades)}')
# Initialize a list of ones
numbers = [1] * 10
print(f'A useful way to create a list is to write [1] * 10 = {numbers}')
# Modify the first and fifth entries
numbers[0] = 4
numbers[4] = 8
print(numbers)

# Modify the last element - negative indices start at the end
numbers[-1] = 9
print(numbers)
# Remove the last element
print(f'Size of list before pop() : {len(numbers)}')
last = numbers.pop()
print(f'Last element is: {last}')
print(f'Size of list before pop() : {len(numbers)}')<jupyter_output>Size of list before pop() : 10
Last element is: 9
Size of list before pop() : 9<jupyter_text>LoopsOften we will want to iterate or loop over a list. We do this using a `for` loop. There are a couple different ways to write a loop. Notice the difference?<jupyter_code>for grade in my_grades:
    print(grade)
for i in range(len(my_grades)):
    print(f'Homework #{i} Grade: {my_grades[i]}')
# Compute the average of homework grades
avg_grade = 0
for grade in my_grades:
    avg_grade += grade
print(f'Average homework grade: {avg_grade / len(my_grades)}')
# Or as a one-liner
print(f'Average homework grade: {sum(my_grades) / len(my_grades)}')
# To build a list of evens from "numbers"

print(f'Find the even numbers from the list: {numbers}')
evens = []
for num in numbers:
    if num % 2 == 0:
        evens.append(num)
print(f'Even numbers: {evens}')<jupyter_output>Find the even numbers from the list: [4, 1, 1, 1, 8, 1, 1, 1, 1]
Even numbers: [4, 8]<jupyter_text>List Comprehensions and GeneratorsList comprehensions are powerful, compact expressions that allow us to more elegantly write code that effectively does the same thing as a `for` loop, but much more concisely and efficiently. The have the following format```( for  in  if )```<jupyter_code># Create a list of numbers from 0 to 11
numbers = [x for x in range(11)]
print(f'Create a list of numbers: {numbers}')
odds = [x for x in range(11) if x % 2 != 0]
print(f'Create a list of odd numbers: {odds}')
squares = [x**2 for x in range(10)]
print(f'A list of squares: {squares}')
# We can also crete generators, which encode instructions for how to generate data
generate_squares = (x**2 for x in range(10))

# Notice what gets printed
print(generate_squares)
# Generators get "consumed"
sum_of_squares = sum(generate_squares)
print(sum_of_squares)

# "generate_squares" still has the same address, but it has been consumed
# and its sum is zero.
print(generate_squares)
print(sum(generate_squares))
get_a_number = (x for x in range(100))

# Get numbers from the generator
a = next(get_a_number)
print(a)
b = next(get_a_number)
print(b)<jupyter_output>0
1
{'fraction_non_alphanumeric': 0.09164484646512736, 'fraction_numerical': 0.016186622232801713, 'mean_word_length': 5.002857142857143, 'pattern_counts': {'":': 0, '<': 10, '<?xml version=': 0, '>': 10, 'https://': 0, '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': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '311347', 'license': 'MIT', 'n_tokens_mistral': 1335, 'n_tokens_neox': 1245, 'n_words': 592, 'path': 'Notebooks/Basics/BasicOperations.ipynb', 'repo_name': 'jcschulz/ae269', 'size': '4201'}