• בלוג
  • יומי
  • כשהשפה עובדת אתך - פיתרון Advent Of Code 2024 יום ראשון ב Ruby

כשהשפה עובדת אתך - פיתרון Advent Of Code 2024 יום ראשון ב Ruby

04/01/2025

האידאולוגיה של רובי היא לתת למתכנתים שפה שפשוט יש בה הכל, כי תכל'ס יותר כיף להשתמש בפונקציה מובנית בשפה מאשר להעתיק מימוש משעמם מ Chat GPT. הנה שתי דוגמאות מפיתרון היום הראשון של Advent Of Code האחרון לפונקציות שקשה למצוא במקומות אחרים.

1. חלק 1 - הפונקציה transpose

הקלט של החלק הראשון בתרגיל מורכב משני טורים:

3   4
4   3
2   5
1   3
3   9
3   3

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

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

filename = ARGV[0]
left, right = File.foreach(filename).map(&:split).transpose

left = left.map(&:to_i).sort
right = right.map(&:to_i).sort

puts (left.each_with_index.map do |value, index|
  (value - right[index]).abs
end).sum

פונקציית transpose לוקחת מערך של זוגות והופכת אותו לשתי רשימות, הרשימה הראשונה של כל "הראשונים" והרשימה השנייה של כל "השניים". בפועל קריאת הקובץ לשני טורים היא בסך הכל השורה:

left, right = File.foreach(filename).map(&:split).transpose

2. חלק 2 - הפונקציה tally

הפונקציה השניה לפוסט נקראת tally והיא מתודה של מערך שמחזירה hash עם מספר המופעים של כל איבר במערך. היא קיימת גם במקומות אחרים אבל קצת יותר קשה להגיע אליה שם, לדוגמה בפייתון היא נקראת Counter שמורה במודול נפרד. ב JavaScript כבר נצטרך את lodash בשביל זה (או לכתוב משהו לבד).

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

filename = ARGV[0]
left, right = File.foreach(filename).map {it.split.map(&:to_i)}.transpose
count = right.tally

puts (left.map do |value|
  value * count.fetch(value, 0)
end).sum

הפעם בגלל שלא היה מיון העברתי את to_i פנימה לשורת הקריאה יחד עם ה split, והשתמשתי בכתיב ה it החדש של רובי 3.4.