השוואת פיתרונות קורס Python

קשוח אתה… טוב סמן לך שכשנגיע לפונקציות אשמח לחזור לפיתרון הזה ולנסות להפוך אותו לקריא יותר

מאה אחוז , תודה רבה !!

לא קשוח :slight_smile:

אבל לפחות זה עובד. לא היה קל…

הי, נסיתי בכל זאת לחלק לפונקציות וגם הוספתי תיעוד

import sys
from collections import Counter

path = sys.argv[1]
words_list = []

def make_list(path):      # make a liast from the words in the file 
    with open(path,'r') as anagram:
        for line in anagram:
            words_list.append(line.strip())
        return words_list


def compare_dictionaries(words_list):    # compare all the words in the list using Counter function
    ref = {}
    print_list = []
    for index,word in enumerate(words_list):
        for element in words_list[index+1:]:
            if len(element) == len(word):
                e = Counter(element)
                w = Counter(word)
                for k,v in e.items():
                    if  k in w.keys() and w[k] == v:
                        ref[k] = w[k]    # ref is a reference dictionary to check match of couple words
                if ref == w:
                    print_list.append('{} {}'.format(element,word)) # list of words that match each other 
                    ref = {}                    
                elif word not in print_list:                        # word that doesn't match to other word
                    print_list.append(word)
    return print_list


def to_print(print_list):     # print function                          
    for item in print_list:
        print item


make_list(path)
print_list = compare_dictionaries(words_list)
to_print(print_list)

הפונקציה compare_dictionaries היא הבעיה - היא עושה המון דברים ויצאה מאוד ארוכה. היא גם:

  1. רצה על כל המילים כדי ״להתאים״ כל מילה לכל מילה אחרת
  2. וגם בודקת אם שתי מילים הן אנאגרמה אחת של השניה

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

חוץ מזה לא ברור לי למה צריך את המשתנה print_list- לא עדיף פשוט להדפיס כל זוג איך שאתה מוצא אותו?

זה הכי טוב שהצלחתי

import sys
from collections import Counter

path = sys.argv[1]
words_list = []
print_list = []

def make_list(path):      # make a list from the words in the file 
    with open(path,'r') as anagram:
        for line in anagram:
            words_list.append(line.strip())
        return words_list


def couple_list(words_list):    # function that return list of couples
    couples = []
    for index,word in enumerate(words_list):
        for element in words_list[index+1:]:
            if len(element) == len(word):
                temp = (element,word)
                couples.append(temp)
    return couples       


def anagram_test(couples):               
    ref = {}
    print_list = []
    for item in couples:
        word_1 = Counter(item[0])
        word_2 = Counter(item[1])
        for k,v in word_1.items():
            if  k in word_2.keys() and word_2[k] == v:
                ref[k] = word_2[k]
        if ref == word_2:
            print item[0],item[1] 
            print_list.append(item[0])      # print_list is for find the single values later
            print_list.append(item[1])
            ref = {}
    couples = couple_list(words_list)
    for i in words_list:                    # This is for the single values 
        if i not in print_list:
            print i

   
            

  
make_list(path)
couples = couple_list(words_list)
anagram_test(couples)

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

לא הבנתי.
מה עם הפונקציה הזאת?

def anagram_test(couples):               
    ref = {}
    print_list = []
    for item in couples:
        word_1 = Counter(item[0])
        word_2 = Counter(item[1])
        for k,v in word_1.items():
            if  k in word_2.keys() and word_2[k] == v:
                ref[k] = word_2[k]
        if ref == word_2:
            print item[0],item[1]

ומהבדיקה שלי , מגיעים לתוצאה הרצויה.

היא גדולה מדי ולכן קשה להבין מה המטרה שלה.

אני חושב על פונקציה כמו מילה חדשה בשפה. כמו שיש את print ו keys ו len כך אתה יכול להוסיף מילים חדשות ואז להשתמש בהן בבניית התוכניות שלך. הפונקציה anagram_test היא לא מילה. אין שום מקום שאתה משתמש בה בתוך בלוק אחר כדי לכתוב משפט מורכב יותר.

תחשוב איך זה היה נראה אם היתה לנו פונקציה is_anagram והיינו בוחרים שם אחר לפונקציית בניית הזוגות שלך:

for word_1, word_2 in word_pairs(words):
  if is_anagram(word_1, word_2):
    print word_1, word_2

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

יותר ברור?

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

תרגיל 1 רשימות

letter = [chr(x) for x in range(97,123)]
לייק 1

תרגיל 2 רשימות

import sys
final_shared = []

temp_shared = [x for x in sys.argv[1] for y in sys.argv[2] if x == y]

כדי להוריד כפילויות:

for letter in temp_shared:
    if letter not in final_shared:
        final_shared.append(letter)

for i in final_shared:
    print i,

ניסיתי להוריד כפילויות בשיטה אחרת (בשורה אחת) אבל זה לא עבד משום מה… אשמח לדעת למה.

final_shared = [letter for letter in temp_shared if letter not in final_shared]


תרגיל 3 רשימות

'''
list of small letters (aaa,aab...)
'''

a = [chr(x) for x in range(97,123)]
b = [chr(x) for x in range(97,123)]
c = [chr(x) for x in range(97,123)]

letters = [x + y + z for x in a for y in b for z in c ]

for i in letters:
    print i,
לייק 1

לשאלה לגבי הכפילויות - אי אפשר להשתמש ב final_shared בתוך שורת הרכבת הרשימות כי עדיין אין לו ערך (יהיה לו ערך רק בסוף הלולאה)

תרגיל 1 פונקציות

def mysum(*nums):

    result = sum([int(x) for x in nums if type(x) == int])
    return result
   
def mymul(*nums):
    mul =1
    for i in nums:
        if type(i) == int:
             mul *= i
    return mul


# returns 30
summary = mysum(10, 'foo', 'bar', 20)
print summary

# returns 200
multiply = mymul('foo', 'bar', 10, 20)
print multiply

אז דיברנו על פונקציות :slight_smile:

הנה רעיון אחר לחלוקה:

def select_ints(list):
  return [x for x in list if type(x) == int]

def mysum(*list):
  return sum(select_ints(list))

def fold(op, list):
  res = list[0]
  for n in list[1:]:
    res = op(res, n)
  return res

def operator_mul(x, y):
  return x * y

def mymul(*list):
  return fold(operator_mul, select_ints(list))

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

אגב- גם שהפונקציה fold וגם הפונקציה operator_mul שהגדרתי כבר קיימות בפייתון בשמות אחרים (תוכל בהזדמנות לחפש) כך שבתוכנית בעולם האמיתי אפילו לא צריך להגדיר אותן כל פעם מחדש.

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

לא הבנתי עד הסוף מה עשית כאן :frowning_face:

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

  • בפונקציה (select_ints(list הארגומנט לא מופיע עם * ז"א שאפשר לקבל רשימה של פרמטרים גם ללא * ?

  • לגבי הפונקציה (fold(op, list לא לגמרי הבנתי. גם שם אין * ולא הבנתי אותה עד הסוף. אני מאמין שבשורה
    (res = op(res, n התכוונת לקרוא לפונקציה (operator_mul(x, y והתפקשש לך ?

  • בפונקציה (mymul(*list הפרמטר operator_mul לא קשור לפונקציה (operator_mul(x, y הוא רק פרמטר שנשלח לפונקציה fold נכון?

  • באופן כללי ה main של התוכנית היה נראה כך (?) :

mysum(any list of parameters)
mymul(any list of parameters)
  • תראה זאת כבר רמה של מקצוענים, בשלב שאני נמצא בו לא הייתי חושב על כזאת מורכבות. איך בעצם השיטה לעבוד כדי לחשוב על כ"כ הרבה קומבינציות?

  • שאלה נוספת - איך אפשר לדבג את התוכנית שלי באמצעות VSC? ניסיתי ע"י mpdb- ב CLI אבל הוא לא נכנס לפונקציות עצמן , רק ל main. ובכלל אני רוצה לדעת איך לדבג ע"י VSC.

תודה, עמיר

הי,

התשובה ארוכה אבל אני רוצה להתחיל במשפט הכי חשוב בה:

הכי חשוב

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

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

(וזה ממש בסדר אם ההסבר או ההצעה שלי לא הכי ברורים עכשיו ויהיו יותר ברורים ככל שתתקדם. המטרה להסתכל על ״איך משתמשים בפונקציות״ ולא על המימוש של הפונקציות עצמן)

כל השאר

ה main יראה בדיוק כמו שלך כלומר שתי אלו עובדות:

mysum(1, 2, 'foo', 'bar', 5)

mymul(10, 20, 'xyz', 60)

לגבי דיבג ב VSC אין לי ניסיון עם זה. יש את PyCharm ששם הדיבג ממש פשוט אז אתה יכול להוריד (בחינם) ולראות אם אתה מסתדר איתו יותר טוב מאשר עם VSC. זה הקישור להורדה:


(צריך לבחור את גירסת ה Community)

עכשיו לגבי שאר הנושאים בוא נתחיל עם הכוכבית-

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

def f_without_star(list):
  print len(list)

def f_with_star(*list):
  print len(list)

f_without_star([10, 20, 3])

f_with_star(10, 20, 30)

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

כשמעבירים לפונקציה מבחוץ מערך לא צריך לכתוב בפנים את הכוכבית כלומר הקוד הבא גם מדפיס 3:

items = [10, 20, 30]
f_without_star(items)

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

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

לגבי fold דוקא כתבתי בדיוק את מה שהתכוונתי - וזה מה שנחמד פה. שים לב איך מפעילים אותה:

fold(operation_mul, [2, 3, 5])

מה שהפונקציה הזו תעשה זה לקחת את הפונקציה operation_mul ולהפעיל אותה על 2 ו-3 (התוצאה: 6), ואז תמשיך ותפעיל אותה שוב על התוצאה הקודמת 6 והמספר החדש 5 (התוצאה: 30). לכן תוצאת הפונקציה היא 30.

אבל נניח שהיתה לנו פונקציה אחרת בשם operator_sum שנראית כך:

def operator_sum(x, y):
  return x + y

עכשיו אתה יכול לחזור ל fold ולכתוב למשל את הקוד:

fold(operator_sum, [2, 3, 5])

והתוצאה של זה תהיה 2+3+5 כלומר 10.

הפונקציה fold לוקחת פונקציה אחרת שמתארת פעולה לביצוע ורשימה ומבצעת את הפעולה על כל שני איברים ברשימה.

לייק 1

מלך אתה !!! תודה !!!

אני מנסה ליישם את התובנות הללו,
להלן תרגיל 2 בפונקציות (אני מקווה שאני מתחיל להבין את הקונספט)

def two_params(a,b):
    for item in [a,b]:
        if all_int(a,b):
            raise Exception("Only one int required")
        if all_str(a,b):
            raise Exception("Only one str required")
    print a,b

def all_int(a,b):
    if type(a) == int and type(b) == int:
        return True

def all_str(a,b):
    if type(a) == str and type(b) == str:
        return True

תרגיל 3 פונקציות

""" The function cakaulate the
tens didit"""

def tens_digit(*nums):
    res = 0
    char = ''
    num_list = []

    for num in nums:
        char = to_str(num)
        num_list = to_list(char)
        if len(num_list) > 1:
            res += int(num_list[-2]) 
    return res


def to_str(num):
    return(str(num))


def to_list(char):
    num_list = [x for x in char]
    return num_list

#print 12
print tens_digit(20,180,220,1)

לגבי תרגיל 2 - אני חושב שהפעם נסחפת עם הפונקציות. נסה לכתוב את זה בלי ותראה אם יוצא יותר פשוט

לגבי תרגיל 3 - הפונקציה to_str ו to_list קטנות מדי. הן מחליפות ביטויים שהם נורא בסיסיים בשפה אז לא בטוח שיש טעם להתאמץ שם.

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

def tens_digits(*numbers):
  return sum([tens_digit_of(x) for x in numbers])