[2021-Fall] Lab06 of CS61A of UCB


Mutability


Write a function which takes in a list lst, an argument entry, and another argument elem. This function will check through each item in lst to see if it is equal to entry. Upon finding an item equal to entry, the function should modify the list by placing elem into lst 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 and elem 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 iterator t and returns the number of times the value x appears in the first n elements of t. 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 least n elements.

這一道題主要是要讓我們學會使用 iternext 這兩個函數. 我們可以用 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 iterator t and returns the first value in t that appears k times in a row.

Note: You can assume that the iterator t will have a value that appears at least k times in a row. If you are receiving a StopIteration, your repeated 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.

我們在這個問題重要解決兩個問題:

  1. 如何找到連續的 k 個值 ? 需要設置 last_val 來記住上一個值是什么, 這樣才能和當前的值進行對比. 用一個 while True: 來不斷找即可(題目保證一定找得到, 所以不用怕死循環)
  2. 如何保證下一次調用的時候要從上一次離開的位置開始 ? 如果認真看過課程的人可能記得要怎么做, 我們應該用高階函數, 在 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)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM