• בלוג
  • חיפוש סיפרה כפולה ב Clojure בהשוואה לפייתון

חיפוש סיפרה כפולה ב Clojure בהשוואה לפייתון

05/12/2019

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

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

def chunks(seq):
    chunk = []

    for val in seq:
        if len(chunk) == 0:
            chunk.append(val)
            continue

        if chunk[-1] == val:
            chunk.append(val)
            continue

        yield(chunk)
        chunk = [val]

    else:
        yield(chunk)

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

import itertools

def find_sequence_of_size(number, sequence_size=2):
    for key, chunk in itertools.groupby(str(number)):
        if len(list(chunk)) == sequence_size:
            return True

    return False

בקלוז'ר הפיתרון ממש דומה ואני חושב שזה נחמד שפונקציות עזר שאנחנו רגילים אליהן משפה אחת מוצאות את דרכן גם לשפות אחרות. ל groupby הם קוראים כאן partition-by אבל אנחנו לא לוקחים ללב הבדלים בשמות.

הקוד המתאים בקלוז'ר נראה כך:

(defn only-two-adjacent-digits
  [num]
  (let [
        snum (str num)
        chunks (partition-by identity snum)
        ]
    (not (empty? (filter (fn [chunk] (= (count chunk) 2)) chunks)))))