Mutability
Write a function which takes in a list
lst
, an argumententry
, and another argumentelem
. This function will check through each item inlst
to see if it is equal toentry
. Upon finding an item equal toentry
, the function should modify the list by placingelem
intolst
right after the item. At the end of the function, the modified list should be returned.See the doctests for examples on how this function is utilized.
Important: Use list mutation to modify the original list. No new lists should be created or returned.
Note: If the values passed into
entry
andelem
are equivalent, make sure you're not creating an infinitely long list while iterating through it. If you find that your code is taking more than a few seconds to run, the function may be in a loop of inserting new values.
注意我們不能 for
循環來一邊遍歷這個 list
一邊進行修改, 我記得我之前在《Effective Python》看過這一點. 其實自己 debug 就可以發現, 因為一開始用 for i in range(len(lst))
的時候就固定了, 但其實你在 for
循環里面會插入新的值, 這個 list
其實是變得更長的(但是 i
還是在原來的范圍里), 所以后面超過本來長度的元素就會看不到.
注意下面這個代碼是錯誤的🙅♂️
def insert_items(lst, entry, elem):
is_the_same = (entry == elem)
while True:
no_entry = True
for i in range(len(lst)):
if lst[i] == entry:
if i == len(lst) - 1:
lst.append(elem)
else:
lst.insert(i + 1, elem)
no_entry = False
# avoid infinite loop
if is_the_same:
i += 1
if no_entry:
return lst
正確的解法應該是用 while
循環搭配 list.index(x[, start[, end]])
方法, 代碼如下:
def insert_items(lst, entry, elem):
"""Inserts elem into lst after each occurence of entry and then returns lst.
>>> test_lst = [1, 5, 8, 5, 2, 3]
>>> new_lst = insert_items(test_lst, 5, 7)
>>> new_lst
[1, 5, 7, 8, 5, 7, 2, 3]
>>> double_lst = [1, 2, 1, 2, 3, 3]
>>> double_lst = insert_items(double_lst, 3, 4)
>>> double_lst
[1, 2, 1, 2, 3, 4, 3, 4]
>>> large_lst = [1, 4, 8]
>>> large_lst2 = insert_items(large_lst, 4, 4)
>>> large_lst2
[1, 4, 4, 8]
>>> large_lst3 = insert_items(large_lst2, 4, 6)
>>> large_lst3
[1, 4, 6, 4, 6, 8]
>>> large_lst3 is large_lst
True
>>> # Ban creating new lists
>>> from construct_check import check
>>> check(HW_SOURCE_FILE, 'insert_items',
... ['List', 'ListComp', 'Slice'])
True
"""
pos, cnt = 0, 0
for i in lst:
if i == entry:
cnt += 1
while cnt > 0:
idx = lst.index(entry, pos)
pos = idx + 1
if idx == len(lst) - 1:
lst.append(elem)
else:
lst.insert(idx + 1, elem)
cnt -= 1
return lst
Iterators
Q4: Count Occurrences
Implement
count_occurrences
, which takes in an iteratort
and returns the number of times the valuex
appears in the firstn
elements oft
. A value appears in a sequence of elements if it is equal to an entry in the sequence.Note: You can assume that
t
will have at leastn
elements.
這一道題主要是要讓我們學會使用 iter
和 next
這兩個函數. 我們可以用 while n > 0
來控制只訪問前 n
個位置, 做一個簡單的判讀來計數即可
def count_occurrences(t, n, x):
"""Return the number of times that x appears in the first n elements of iterator t.
>>> s = iter([10, 9, 10, 9, 9, 10, 8, 8, 8, 7])
>>> count_occurrences(s, 10, 9)
3
>>> s2 = iter([10, 9, 10, 9, 9, 10, 8, 8, 8, 7])
>>> count_occurrences(s2, 3, 10)
2
>>> s = iter([3, 2, 2, 2, 1, 2, 1, 4, 4, 5, 5, 5])
>>> count_occurrences(s, 1, 3)
1
>>> count_occurrences(s, 4, 2)
3
>>> next(s)
2
>>> s2 = iter([4, 1, 6, 6, 7, 7, 8, 8, 2, 2, 2, 5])
>>> count_occurrences(s2, 6, 6)
2
"""
it = iter(t)
cnt = 0
while n > 0:
val = next(it)
if val == x:
cnt += 1
n -= 1
return cnt
Q5: Repeated
Implement
repeated
, which takes in an iteratort
and returns the first value int
that appearsk
times in a row.Note: You can assume that the iterator
t
will have a value that appears at leastk
times in a row. If you are receiving aStopIteration
, yourrepeated
function is likely not identifying the correct value.Your implementation should iterate through the items in a way such that if the same iterator is passed into
repeated
twice, it should continue in the second call at the point it left off in the first. An example of this behavior is in the doctests.
我們在這個問題重要解決兩個問題:
- 如何找到連續的
k
個值 ? 需要設置last_val
來記住上一個值是什么, 這樣才能和當前的值進行對比. 用一個while True:
來不斷找即可(題目保證一定找得到, 所以不用怕死循環) - 如何保證下一次調用的時候要從上一次離開的位置開始 ? 如果認真看過課程的人可能記得要怎么做, 我們應該用高階函數, 在
repeated
里面再定義一個函數, 將變量綁定到這個嵌套的函數上. 這樣我們就可以保證每次都可以從上一次的位置開始. 忘了的可以看看這個鏈接 的 2.4.4 Local state
def repeated(t, k):
"""Return the first value in iterator T that appears K times in a row.
Iterate through the items such that if the same iterator is passed into
the function twice, it continues in the second call at the point it left
off in the first.
>>> s = iter([10, 9, 10, 9, 9, 10, 8, 8, 8, 7])
>>> repeated(s, 2)
9
>>> s2 = iter([10, 9, 10, 9, 9, 10, 8, 8, 8, 7])
>>> repeated(s2, 3)
8
>>> s = iter([3, 2, 2, 2, 1, 2, 1, 4, 4, 5, 5, 5])
>>> repeated(s, 3)
2
>>> repeated(s, 3)
5
>>> s2 = iter([4, 1, 6, 6, 7, 7, 8, 8, 2, 2, 2, 5])
>>> repeated(s2, 3)
2
"""
assert k > 1
last_val, it = None, iter(t)
def helper(k):
nonlocal last_val
nonlocal it
cnt = 0
while True:
val = next(it)
if last_val is None or val != last_val:
last_val, cnt = val, 1
else:
cnt += 1
if cnt == k:
return val
return helper(k)