קורס Python 3 שיעור תרגול מבני נתונים


זה נושא דיון מלווה לערך המקורי ב- https://www.tocode.co.il/bundles/python/lessons/19-data-lab

אפשר בבקשה לעלות פתרונות לשאלות

הי,

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

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

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

היי @ynonp

הינה התשובה של שאלה 1 :

username_password = {
    'apple' : 'red',
    'lettuce' : 'green',
    'lemon' : 'yellow',
    'orange' : 'orange'
}
print("hello, Please enter your username : ")
username = input()
print("And your password please : ")
password = input()

for u, p in username_password.items():
    if username == u and password == p:
        print("Access guaranteed")
    else :
        print("Wrong Credentials")

אני קצת רוצה לשפץ את הקוד:
עם אנחנו נשים ב INPUT של שם משתמש orange ובסיסמה orange נקבל את 3 פעמים Wrong Credentials , אני רוצה שלא נדפיס 3 פעמים את Wrong Credentials אלה רק אחרי שבדקנו את הכל נדפיס פעם אחת Access guaranteed או Wrong Credentials.

תוכל לעזור לי לשפץ את הקוד? :slight_smile:

@ynonp

וזאת התשובה של שאלה 2 :

import sys

User_numbers = sys.argv[1:21]
sum_of_numbers = sum(map(int,User_numbers))
print(f"The sum of the grades is: {sum_of_numbers}")

avarage = sum_of_numbers / len(User_numbers)
print(f"The Average of the grades is: {avarage}")

switch_to_integer = [int(n) for n in User_numbers]

grades_more_then_average = []
for per_grade in switch_to_integer :
    if per_grade > avarage:
        grades_more_then_average.append(per_grade)
print(f"The grades which are more then the average are {grades_more_then_average}")

אני חושב שיש בעיה עם השורה הזאת:

for u, p in username_password.items():

אין סיבה לבדוק את כל הערכים במילון - מספיק לשלוף את ה key/value pair שמעניינים אותך. יש לך רעיון איך?

היי @ynonp

יש לי את התשובה :

 username_password = {
    'apple' : 'red',
    'lettuce' : 'green',
    'lemon' : 'yellow',
    'orange' : 'orange'
}
print("hello, Please enter your username : ")
username = input()
print("And your password please : ")
password = input()
if (username , password) in username_password.items() :
    print("Access guaranteed")
else :
    print("Wrong Credentials")

היי @ynonp

הינה התשובה של שאלה 3 :

print("Hello user please write your computer name and i will provide your IP address")
while True:
    computer_name = input()
    all_computers = {}

    with open('host.txt', 'r') as host_file :
        for line in host_file:
            (key, val) = line.replace("\n", '').split('=')
            all_computers[key] = val

        if computer_name in all_computers.keys():
            print(f"Your ip is : {all_computers[computer_name]}")
            print("Nice you got your ip!")
            print("Write another computer name")
        else:
            print("Your computer name is not existing in our list")
            print("Write your computer name again :")

לא מדויק. נסה לקרוא את זה ולראות אם אתה מבין את הבעיה:

אם הבנת ספר כאן מהי, אם לא ספר מה כן הבנת ונמשיך משם

לייק 1

הפתרונות שלי.

  • תרגיל 1 (עם לולאה אינסופית לחזרה על הבדיקה):
user_access_table = {
    'apple':    'red',
    'lettuce':  'green',
    'lemon':    'yellow',
    'orange':   'orange',
}


def check_user_access(user_name, password):
    """
    Gets username and password, and check them at user_access_table.
    If OK prints 'Welcome Master' and return True, otherwise prints
    'INTRUDER ALERT' and return False.
    :param user_name: user name string.
    :param password: the password string matching the given username.
    :return: True on exact mach, False otherwise.
    """
    try:
        if user_access_table[user_name] == password:
            print('Welcome Master')
            return True
    except KeyError:
        pass

    print('INTRUDER ALERT')
    return False


while True:
    user_name = input('Username: ')
    password = input('Password: ')
    check_user_access(user_name, password)
  • תרגיל 2:
import sys

number_of_expected_grades = 20
grades_list = []
try:
    for i in range(1, number_of_expected_grades + 1):
        grades_list.append(int(sys.argv[i]))
except ValueError:
    print(f'Expected grades to be numerical, but grade#{len(grades_list) + 1} is: "{sys.argv[len(grades_list) + 1]}".')
    exit(1)
except IndexError:
    print(f'Expected {number_of_expected_grades} grades, but got:', len(grades_list))
    exit(2)

grades_avg = sum(grades_list) / number_of_expected_grades
above_avg = [str(g) for g in grades_list if g > grades_avg]
print('above avg grades:', ' '.join(above_avg))
  • תרגיל 3:
import sys


def get_hosts():
    """
    Parsing a file by the name 'hosts' for servers name and IP address.
    :return: A dict with servers names as keys and their IP addresses as values.
    """
    hosts = {}
    try:
        with open('hosts', 'r', encoding='UTF-8') as f:
            for line in f:
                (server_name, server_address) = line.split('=', 1)
                hosts[server_name] = server_address.rstrip()
    except FileNotFoundError as e:
        print(f'Failed to read hosts file - {e}\nAborting.')
        exit(1)
    return hosts


hosts_dict = get_hosts()
for i in range(1, len(sys.argv)):
    server = sys.argv[i]
    print(f'{server + " IP address:":20}', end=' ')
    try:
        print(hosts_dict[server])
    except KeyError:
        print('not in hosts list.')

דוגמה לפלט (שימוש בקובץ שרתים זהה לדוגמה שניתנה בתרגיל):

λ py 19-data-lab_ex3.py home mobile mycar flor2 work
home IP address:     194.90.2.1
mobile IP address:   not in hosts list.
mycar IP address:    10.0.0.5
flor2 IP address:    not in hosts list.
work IP address:     10.0.0.2
  • תרגיל 4:
    [למרות שזה לא מובן מהגדרת התרגיל, מימשתי אותו כך שיכולות להיות יותר משתי מילים בקובץ שהן אנגרמה. אם אין אפשרות ליותר מ-2 מילים כאלו, אפשר ליעל את התהליך ע"י עצירת הלולאה ברגע שמוצאים את ההתאמה הראשונה.]
import sys


def is_anagram(word1, word2):
    """
    Check if the 2 words given are each others anagram.
    :param word1: 1st word string.
    :param word2: 2nd word string.
    :return: True if they are anagrams, False otherwise.
    """
    sorted_word1 = ''.join(sorted(list(word1)))
    sorted_word2 = ''.join(sorted(list(word2)))
    return True if sorted_word1 == sorted_word2 else False


words_list = []
try:
    with open(sys.argv[1], 'r', encoding='UTF=8') as f:
        for line in f:
            words_list.append(line.rstrip())
except FileNotFoundError as e:
    print(f'Failed to read words file - {e}\nAborting.')
    exit(1)

for i in range(len(words_list)):
    if '' == words_list[i]:
        continue
    for j in range(i + 1, len(words_list)):
        if '' == words_list[j]:
            continue
        if is_anagram(words_list[i], words_list[j]):
            print(words_list[j], end=' ')
            words_list[j] = ''
    print(words_list[i])
לייק 1

בוא נדבר רגע על 4…

בהינתן קובץ עם 8 מילים כמה בדיקות עם is_anagram אתה הולך לעשות? האם אפשר לחשוב על מנגנון שיצטרך פחות השוואות?

בקובץ עם 8 מילים, שאף אחת מהן אינה אנגרמה של אחרת, יבוצעו 28 בדיקות.
כרגע לא מצליח לחשוב על מנגנון שידרוש פחות השוואות.

כפי שכתבתי במאמר המוסגר לפני הקוד של תרגיל 4:

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

בקובץ בו יש מילים שהם אנגרמה למילים אחרות בקובץ, אפשר להקטין את מספר ההשוואות אם יודעים את כמות האנגרמות המירבית.
לדוגמה, אם יהיו לכול היות 2 מילים בקובץ שהן אנגרמה אחת של השנייה, אז אפשר להוסיף break בלולאה הפנימית לאחר זיהוי אנגרמה ולוותר על המשך הבדיקות. כך שבקובץ של 8 מילים עם 4 אנגרמות בשורות עוקבות (4 צמדי מילים, כל אחד בשתי שורות עוקבות) יבוצעו רק 4 בדיקות.
אם מקבלים כמשתנה את מספר המילים המרבי לאנגרמה אחת, אפשר להרחיב את הפתרון הזה עם מונה ובדיקה שלו לפני ה-break

בבעיות מהסוג הזה עוזר לחשוב על חלוקה לקבוצות

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

עכשיו נסה לעשות את אותו דבר עם האנאגרמות

לייק 1

צודק! dict יעיל לדברים כאלו.
קוד לפתרון:

import sys
from collections import defaultdict

sorted_words = defaultdict(list)
try:
    with open(sys.argv[1], 'r', encoding='UTF=8') as f:
        for line in f:
            sorted_words[''.join(sorted(list(line.rstrip())))].append(line.rstrip())
except FileNotFoundError as e:
    sys.exit(f'Failed to read words file - {e}\nAborting.')
except IndexError as e:
    sys.exit('ERROR: Missing mandatory command line argument for words-file path.')

for sorted_word in sorted_words:
    print(' '.join(sorted_words[sorted_word]))

@GuyK הי הנה עוד פוסט שכתבתי על הנושא אולי יעזור לך לשפר את הפיתרון:

#Hello here is my code for Exercice 1. 
#How can I get only one time the print answer when I am entering a bad password? II get it 4 time....Toda ! 






userName = input('Please enter a user name: ')
password = input('Please enter a password: ')

users_full_account = {

    'apple': 'red',
    'lettuce': 'green',
    'lemon': 'yellow',
    'orange': 'orange'
}

for name, login in users_full_account.items():
    if name == userName and password == login:
        print('ok')
    else:
        print('Sorry! wrong credential')

הי דבורה,

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

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

if userName in users_full_account:
    login = users_full_account[name]    
    if password == login:
        print('ok')
    else:
        print('Sorry! wrong credential')
else:
        print('Sorry! wrong credential')

עוד כמה נקודות קטנות לגבי סגנון כתיבה ופייתון:

  1. בשמות משתנים בפייתון שכוללים מספר מילים אנחנו מפרידים את המילים עם קו תחתי, כלומר נשתמש ב user_name ולא ב userName.

  2. לא צריך להשאיר שורה ריקה בתחילת רשימת הערכים של המילון.

  3. מקובל לרשום פסיק גם אחרי הערך האחרון במילון (כי אז יותר קל להוסיף עוד ערך או לעשות קופי-פייסט בין השורות).

Thanks a lot Ynon!  I understand better! Just one question:
I dont understand the why login =  users_full_account[name] 
and what will be the value of login...it is not very clear for me. 
Can you please explain to me?
so how can name == password. Hope my question is clear!? 
thanks so much for the help! Dvorah 

I used the name login to match the variable names you selected in your program, but of course you don’t need this assignment line and things will work just as will if you use:

if userName in users_full_account:
  if password == users_full_account[userName]:
    print('ok')

or even the shorter version:

if userName in users_full_account and password == users_full_account[userName]:
  print('ok')