<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Unit 3
Step1:  4b. Repeat Question 2a and 2b for a NumPy array
Step2:  10b. Now run the code, did the contents of list1 change?
10c. If you called the change function on array1, would the contents of array1 change?
10d. Explain the behavior that you see when you run the change function on a list or array.
11a. Before you run the code in the cell below, predict what you think will print.
Step3:  11b. Now run the code, Did the contents of list1 change?
11c. If you called the change_first function on array1, would the contents of array1 change?
11d. Explain the behavior that you see when you run the change_first function on a list or array.
Model 2
Step4:  12b. Analysis
Step5:  13b. Analysis
Step6:  14b. Analysis
Step7:  15b. Analysis
Step8:  16b. Analysis
Step9:  17b. Analysis
Step10:  18b. Analysis
Step11:  Write and run code that makes a new list, called squares that contains the squares of the values in original using a for loop.
Step12:  24a. Explain the results of the list comprehension above.
24b. How does the list comprehension work?
Write and run code that makes a new list, called evens that contains the even values from original using a for loop.
Step13:  25a. Explain the results of the list comprehension above.
25b. How does the list comprehension work?
Write and run code that uses a loop or loops to make the following list of tuples that contain an integer and its square
<ASSISTANT_TASK:>
Python Code:
## don't forget to
import numpy as np
Explanation: Unit 3: Simulations
Lesson 24: Advanced Lists
Notebook Authors
(fill in your two names here)
Team Roles
Facilitator: (fill in name)
Spokesperson: (fill in name)
Process Analyst: (fill in name)
Quality Control: (fill in name)  
If there are only three people in your team, have one person serve as both spokesperson and process analyst for the rest of this activity.<p>
At the end of this Lesson, you will be asked to record how long each Model required for your team. The Facilitator should keep track of time for your team.
Computational Focus: Programming with Collections of Data
Model 1: References versus Copies
When programming with collections of data (such as lists and arrays), it’s critical to understand when a variable is referring to an item in the original collection and when a variable is referring to copy of the original item:  
Critical Thinking Questions
1a. Before you run the code below, write a prediction of the results in the MD cell below. 
Type and run the lines of code below in a code cell:  
python
list1 = list(range(5))
for i in list1:
    i = i*2
print(list1)
It may also help to view the visualization of this code running in Python Tutor.
1b. Did the collection (list1) change?
2a. Before you run the code below, write a prediction of the results in the MD cell below.   
Type and run the lines of code below in a code cell:  
python
list2 = list(range(5))
for i in range(len(list2)):
    list2[i] = list2[i]*2
print(list2)
Again, you should view the visualization of this code running in Python Tutor.
2b. Did the collection (list2) change?
3. Describe the difference between the two for-loops you used for a list with respect to: 
3a. the difference in syntax.
3b. the difference in behavior.
4. Using similar code as Questions 1 and 2, answer the same questions for a NumPy array. Determine the difference in behavior for a NumPy array: 
4a. Repeat Question 1a and 1b for a NumPy array:
End of explanation
## Q10 code
def change(item):
    item = 100
print("before", list1)
change(list1[0])
print("after", list1)
Explanation: 4b. Repeat Question 2a and 2b for a NumPy array:
4c. Repeat Question 3b for a NumPy array: 
5. Summarize the similarities and differences between arrays and lists in this context.
6. Using similar code as Questions 1 and 2, answer the same questions for a string.
7. Using similar code as Questions 1 and 2, answer the same questions for a tuple.
8. What are the differences between:
8a. the string - tuple group and the list - array group? Explain.
8b. the two for-loop approaches (from Questions 1 and 2)? Explain.
9. Consider the two approaches using for-loops shown in Questions 1 and 2 above.    
9a. When would it be better to use the first for-loop approach when programming with a collection of data?
9b. When would it be better to use the second for-loop approach when programming with a collection of data? 
10a. Before you run the code in the cell below, predict what you think will print.
End of explanation
## Q11 code
def change_first(collection):
    collection[0] = 100
print("before", list1)
change_first(list1)
print("after", list1)
Explanation: 10b. Now run the code, did the contents of list1 change?
10c. If you called the change function on array1, would the contents of array1 change?
10d. Explain the behavior that you see when you run the change function on a list or array.
11a. Before you run the code in the cell below, predict what you think will print.
End of explanation
## Q12 code
x = 0
y = x
y = 50
print(x)
Explanation: 11b. Now run the code, Did the contents of list1 change?
11c. If you called the change_first function on array1, would the contents of array1 change?
11d. Explain the behavior that you see when you run the change_first function on a list or array.
Model 2: Assignments
We also need to be understand when we assign a new variable to an existing collection of data, whether we are referring to the original collection or a copy of the entire collection:
For each of the code cells below, predict the output BEFORE running them ("prediction"), then run and comment on whether the original variable changed or not ("analysis").
12a. Prediction:
End of explanation
## Q13 code
list1 = list(range(5))
list2 = list1
list2[0] = 50
print(list1)
Explanation: 12b. Analysis:
13a. Prediction:
End of explanation
## Q14 code
list3 = list(list1)
list3[0] = 100
print(list1)
Explanation: 13b. Analysis:
14a. Prediction:
End of explanation
## Q15 code
array1 = np.array(range(5))
array2 = array1
array2[0] = 50
print(array1)
Explanation: 14b. Analysis:
15a. Prediction:
End of explanation
## Q16 code
array3 = np.array(array1)
array3[0] = 100
print(array1)
Explanation: 15b. Analysis:
16a. Prediction:
End of explanation
## Q17 code
dictionary1 = {"A":"alpha", "B":"beta", "C":"gamma"}
dictionary2 = dictionary1
dictionary2["A"] = "first letter"
print(dictionary1)
Explanation: 16b. Analysis:
17a. Prediction:
End of explanation
## Q18 code
dictionary3 = dict(dictionary1)
dictionary3["A"] = "T"
print(dictionary1)
Explanation: 17b. Analysis:
18a. Prediction:
End of explanation
## run this code to make a list
original = list(range(5))
print(original)
Explanation: 18b. Analysis:
Critical Thinking Questions
19. What is the default behavior of an assignment (=) in Python? In other words, does it make a second reference to an original collection, or does it make a copy of the entire collection?
20. What syntax is required to produce the opposite behavior (not the default behavior)?
21. In your own words, explain the main idea from this model.
22. Does this main idea apply to strings? 
23. Here are two additional ways to make copies of a collection. Test whether they give you a second reference to the original collection or whether they make a copy of the entire collection, and describe your findings (try each method on each indicated data type):
23a. for lists and arrays, test a slice with no values and describe the results (copy or reference?). 
list4 = list1[:]
23b. for arrays and dictionaries, test the copy method and describe the results (copy or reference?).
array4 = array1.copy()
Model 3: List Comprehension
We first saw list comprehensions very breifly in our first lesson on random numbers.
List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operation(s) applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition (reference).  
A well written list comprehension can often take the place of a for loop.
Let's work through some examples.
End of explanation
## run this code to make a new list of squares of original
## this version uses list comprehension
squares_lc = [x**2 for x in original]
print(squares_lc)
Explanation: Write and run code that makes a new list, called squares that contains the squares of the values in original using a for loop.
End of explanation
## run this code to make a new list of even numbers from original
## this version uses list comprehension
evens_lc = [x for x in original if x%2==0]
print(evens_lc)
Explanation: 24a. Explain the results of the list comprehension above.
24b. How does the list comprehension work?
Write and run code that makes a new list, called evens that contains the even values from original using a for loop.
End of explanation
## run this code
## list comprehension of loops below
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
## run this code
## loop version of list comprehension above
combs = []
for x in [1,2,3]:
    for y in [3,1,4]:
        if x != y:
            combs.append((x, y))
combs
## run this code
## list comprehension of loops below
[[x+y for x in ['A', 'B']] for y in ['C', 'D']]
## run this code
## loop version of list comprehension above
list_a = ['A', 'B']
list_b = ['C', 'D']
lcombs = []
for y in list_b:
    for x in list_a:
        lcombs.append([x+y])
lcombs
Explanation: 25a. Explain the results of the list comprehension above.
25b. How does the list comprehension work?
Write and run code that uses a loop or loops to make the following list of tuples that contain an integer and its square:
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
Now write and run code that makes the same results in a single line using list comprehension
Note: you can also have multiple loop replacements in sequential order in a list comprehension or nested inside a list comprehension. Check out the examples below from here and here.
End of explanation
<END_TASK>