לולאות מקוננות (nested loops)

Contents

לולאות מקוננות (nested loops)#

בדומה למשפטי תנאי מקוננים אותם פגשנו, כאן מדובר על לולאה שנמצאת בתוך לולאה אחרת. אם יש שתי לולאות כאלו אחת בתוך השנייה, אז לולאה אחת היא לולאה חיצונית וזו שבתוכה תיקרא לולאה פנימית.

מה שמיוחד במצב הזה הוא, שהלולאה הפנימית תתבצע בעצמה פעמים רבות. כלומר בכל איטרציה של הלולאה החיצונית, הלולאה הפנימית תתחיל להתבצע מחדש.

נתחיל בשאלת הכנה.

מה מדפיס הקוד הבא:

a = 0
b = 5
for i in range(5):
    a = a + 1
b = b - 1  
print(a,b)

שימו לב להזחות - ההגדלה של a ב-1 מוזחת ולכן הקוד הזה מתבצע בתוך הלולאה - בסך הכל 5 פעמים - ולכן ערכו של a הוא 5. לעומת זאת, ההקטנה של b ב-1 אינה מוזחת, ולכן היא לא חלק מהלולאה. כתוצאה מכך, b קטן ב-1 רק פעם אחת (לאחר סיום ביצוע הלולאה), ולכן ערכו של b בסיום הריצה הוא 4.

נציין כי אם b כן היה מוזח אל תוך הלולאה, ערכו הסופי היה 0 (חישבו למה!), ובמקרה זה ההדפסה היתה “0 5”.

לולאות מקוננות הן שתיים או יותר לולאות הנמצאות אחת בגוף של השניה. לדוגמא:

for i in range(10):
    for j in range(10):
        print("i =", i,", j =", j)

כאן הלולאה החיצונית משתמשת במשתנה i ואילו הלולאה הפנימית משתמשת במשתנה j. בכל איטרציה של הלולאה החיצונית, מתבצעת הלולאה הפנימית במלואה.
מועיל לחשוב על הלולאה הפנימית כעל פקודה שנמצאת בתוך הלולאה החיצונית, ומתבצעת בכל איטרציה מחדש. למשל, באיטרציה החיצונית הראשונה, בה 0=i, תתבצע הלולאה הפנימית ו- j ירוץ מ- 0 ועד 10. כך יקרה בכל איטרציה חיצונית בהמשך.

בדוגמה השתמשנו רק בלולאות for, אך ניתן כמובן להשתמש בלולאות מקוננות גם עם לולאות while, וכן לשלב בין הסוגים.

השימוש בלולאות מקוננות לא שונה מהותית משימוש בלולאות רגילות, אך יש לשים דגש מיוחד על ההזחות. כדי שהלולאה הפנימית תהיה חלק מגוף הלולאה החיצונית, עלינו להזיח אותה ימינה.

צפו כעת ברחבה על הדוגמא שהצגנו ללולאות מקוננות:

לנוחיותכם חלונית עם הקוד שראינו בסרטון. מוזמנים להריץ בעצמכם:

def all_pairs(n):
    for i in range(1,n+1):
        for j in range(1, n + 1):
            print("i =", i, ", j =", j)

all_pairs(3)
i = 1 , j = 1
i = 1 , j = 2
i = 1 , j = 3
i = 2 , j = 1
i = 2 , j = 2
i = 2 , j = 3
i = 3 , j = 1
i = 3 , j = 2
i = 3 , j = 3

בחנו את עצמכם

התבוננו בקטע הקוד הבא:

for i in range(3):
    for j in range(7):
        do_something(i, j)

התבוננו בקטע הקוד הבא:

n = 0
while n < 50:
    for i in range(5):
        n = n + i
print("Done")

תרגול#

סכום מכפלת זוגות

בתרגיל זה עליכם לממש את הפונקציה all_pairs_sum שכותרתה מופיעה בחלונית הקוד. זוהי גרסה מעט שונה של הפונקציה all_pairs שאותה הצגנו בסרטון.

הפונקציה all_pairs_sum מקבלת כקלט שני מספרים שלמים וחיוביים - m ו-n. הפונקציה צריכה להחזיר את סכום המכפלות של כל הזוגות של המספרים בהם האיבר הראשון הוא בין 1 ל-m והאיבר השני הוא בין 1 ל-n. בניגוד לפונקציה מהסרטון, פונקציה זו לא צריכה להדפיס שום דבר (אך ניתן כמובן להוסיף הדפסות עזר בעת כתיבת הפתרון).

דוגמה:

נניח כי m=2 ו-n=3. עבור ערכים אלו, נציג תחילה את כל הזוגות בהם המספר הראשון (השמאלי) הוא בין 1 ל-m(כלומר, בין 1 ל-2) והמספר השני (הימני) בין 1 ל-n (כלומר, בין 1 ל-3). כל זוג כזה יופיע בתוך סוגריים עגולים: $\( (1,1), (1,2), (1,3), (2,1), (2,2), (2,3) \)$

עבור ערכים אלו של m ו-n, הפונקציה תחזיר את סכום המכפלות של הזוגות האלו, כלומר, את המספר 18: $\( 1*1 + 1*2 + 1*3 + 2*1 + 2*2 + 2*3 = 1 + 2 + 3 + 2 + 4 + 6 = 18 \)$

def all_pairs(n):
    for i in range(1,n+1):
        for j in range(1,n+1):
            print(i,j)


def all_pairs_sum(m,n):
    # Write your solution here
    pass
    
    

### TESTS ###
tests = [(1,1), (2,3)]
sols = [1, 18]
print("********************")
print("Starting the test:")
for i, (m,n) in enumerate(tests):
    print("********************")
    print("Checking the current values: m =", m, ", n =", n)
    res = all_pairs_sum(m,n)
    if res == sols[i]:
        print("CORRECT: The sum of all pairs is", res)
    else:
        print("WRONG: Your answer is:", res ,", but the correct answer is:", sols[i])

print("********************")    
print("Tests concluded, add more tests of your own below!")
print("********************")
********************
Starting the test:
********************
Checking the current values: m = 1 , n = 1
WRONG: Your answer is: None , but the correct answer is: 1
********************
Checking the current values: m = 2 , n = 3
WRONG: Your answer is: None , but the correct answer is: 18
********************
Tests concluded, add more tests of your own below!
********************

הדפסת מלבנים בתרגיל זה עליכם לממש את הפונקציה print_rectangle שמופיעה בחלונית הקוד. הפונקציה מקבלת כקלט שני מספרים שלמים - height (גובה) ו-width (רוחב). על הפונקציה להדפיס מלבן של סולמיות (#) בגובה וברוחב הנתונים. בכל שורה הסולמיות מופרדות ברווח (ראו דוגמאות בהמשך). הפונקציה לא מחזירה דבר.

דוגמאות הרצה:

הרצה של print_rectangle(1,1)‎ תדפיס סולמית בודדת. הרצה של print_rectangle(3,5)‎ תדפיס:

# # # # #
# # # # #
# # # # #

הנחיות:

  • ניתן להניח כי הקלטים תמיד יהיו מספרים שלמים וחיוביים (כלומר, גדולים מ-0).

  • שימו לב לסדר הקלטים שהפונקציה מקבלת - הגובה הוא הקלט הראשון מבין השניים.

  • כפי שאתם ודאי מבינים, יש צורך להשתמש כאן בלולאות מקוננות.

  • על מנת להדפיס סולמית ללא ירידת שורה, השתמשו בפקודה print(“#”, end=” “)‎. פקודה זו תדפיס סולמית ואחריה רווח, ללא ירידת שורה.

  • שימו לב שבסוף כל שורה במלבן אתם כן צריכים לרדת שורה. תוכלו לעשות זאת על ידי הדפסת מחרוזת ריקה - print(“”)‎

לאחר שסיימתם את כתיבת הקוד, הריצו אותו ובדקו את התוצאות בחלונית הפלט.

def print_rectangle(height, width):
    # Write your solution here
    pass
    
### TESTS ###
print("********************")
print("Starting the test:")
sols=['#', '# # # # #\n# # # # #\n# # # # #']
tests = [(1,1), (3,5)]

for i, (h,w) in enumerate(tests):
    print("********************")
    print("Checking the current values: height =", h, ", width =",w)
    print("Your solution:")
    print_rectangle(h,w)
    print("---------------")
    print("The correct solution:")
    print(sols[i])
print("********************")    
print("Tests concluded, add more tests of your own below!")
print("********************")
********************
Starting the test:
********************
Checking the current values: height = 1 , width = 1
Your solution:
---------------
The correct solution:
#
********************
Checking the current values: height = 3 , width = 5
Your solution:
---------------
The correct solution:
# # # # #
# # # # #
# # # # #
********************
Tests concluded, add more tests of your own below!
********************

עבודה עם רשימות מקוננות

נתונה רשימה מקוננת, כלומר רשימה שכל איבר בה הוא בעצמו רשימה של מספרים. לדוגמה:

A = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

B = [
    [2, 0, 1],
    [1, 3, 2],
    [0, 1, 4]
]

ממשו את הפונקציה elementwise_mult שמקבלת שתי רשימות מקוננות A וB. הפונקציה תערוך את A כך שכל איבר הוא מכפלה של שני האיברים המתאימים באותו מיקום. כלומר, אם באותו מיקום ב־A יש את המספר 5 וב־B יש את המספר 3, בA לאחר הפונקציה יופיע 15. הפונקציה לא צריכה להחזיר דבר.

ניתן להניח שהמימדים של הרשימות A וB זהים.

def elementwise_mult(A, B):
    # write your code here
    pass

כעת ממשו את הפונקציה באופן דומה, אך הפעם נוצרת רשימה חדשה בה כל איבר הוא מכפלה של שני האיברים המתאימים באותו מיקום. כלומר, הפעם יש לוודא שA לא משתנה כלל.

def elementwise_mult_copy(A, B):
    # write your code here
    pass