היום למדתי: שינוי שם שם מפתח במפה בקלוז'ר
הנה פעולה שלא חשבתי שאי פעם אצטרך אבל מסתבר שיש לא מעט איזכורים שלה ברשת בכל מיני שפות, ובינתיים מהשפות שאני מכיר מצאתי שרק קלוז'ר מציעה דרך סטנדרטית להחליף שם של מפתח. אבל לפני הקוד בואו נבין על מה אנחנו מדברים - בשפות תכנות מודרניות יש מבנה נתונים שנקרא "מפה" או "מילון", ובדרך כלל יש המון דברים שאפשר לעשות עם ערכים של מילון אבל מעט דברים לעשות עם המפתחות. הרבה שפות אפילו יצרו מנגנוני הגנה כדי שלא נוכל להשתמש בכל טיפוס נתונים בתור מפתח. לדוגמה בפייתון רשימה לא יכולה להיות מפתח:
>>> d = {}
>>> d[[1, 2, 3]] = 10
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
או ב JavaScript כל מפתח שנבחר יהפוך ל String אוטומטית:
> o = {}
{}
> o[2] = 10
10
> o['2']
10
אם כבר יצרתי מילון עם מפתחות ואני צריך לשנות שם של מפתח ברוב השפות אני אצטרך להוציא את המפתח הישן מהמילון ולהכניס ערך חדש עם מפתח בשם החדש. רובי עושה את זה הכי אלגנטי אבל באמת שאותו טריק עובד בכל מקום:
3.1.1 :001 > h = { name: "ynon" }
=> {:name=>"ynon"}
3.1.1 :002 > h[:nickname] = h.delete :name
=> "ynon"
3.1.1 :003 > h
=> {:nickname=>"ynon"}
היה לי מילון עם מפתח בשם name ובשביל להחליף אותו ל nickname היה צריך להוציא את המפתח הישן מהמילון ולשים חדש עם אותו ערך.
וקלוז'ר? דווקא היא הפתיעה לטובה עם פונקציית rename-keys
שמקבלת מפה ומפה של שינויים ומשנה את השמות של המפתחות לפי מפת השינויים. כמובן שבקלוז'ר אנחנו מדברים על מבני נתונים Immutable ולכן אנחנו לא באמת משנים מילון אלא מייצרים מילון חדש עם המפתחות בשמות החדשים:
user=> (clojure.set/rename-keys {:name "ynon"} {:name :nickname})
{:nickname "ynon"}
מכירים פונקציה כזאת בעוד שפות? אל תתביישו וספרו בתגובות.