• בלוג
  • היום למדתי: סדר המפתחות ב JSON.stringify

היום למדתי: סדר המפתחות ב JSON.stringify

04/10/2021

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

const keys = ['a', 'b'];
const data = [ { a: 10, b: 20, c: 30 }, { a: 10, b: 20, c: 40 }, { a: 10, b: 12, c: 50 } ];

והמשימה היא לסדר את data לקבוצות לפי המפתחות ב keys: כל שני אוביקטים שיש להם בדיוק את אותם ערכים למפתחות במערך keys יהיו באותה קבוצה. בדוגמה שלנו הקבוצה הראשונה תהיה:

const groups1 = [ { a: 10, b: 20, c: 30 }, { a: 10, b: 20, c: 40 } ];

כי לשני האוביקטים בשדה a יש את הערך 10 ובשדה b יש את הערך 20, והקבוצה השניה תהיה האוביקט היחיד:

const group2 = [ { a: 10, b: 12, c: 50 } ];

כי השדה b מכיל בו ערך שונה - הערך 12.

האינטואיציה הראשונה לפיתרון בעזרת lodash היא כנראה הפונקציה groupBy: לוקחים מכל אוביקט רק את המפתחות שמעניינים אותנו, מפעילים עליהם JSON.stringify כדי לקבל מחרוזת וזה יהיה המפתח ל groupBy. הנה הקוד:

// DO NOT USE - HAS A BIG BUG

const groups = _.groupBy(data, obj => JSON.stringify(_.pick(obj, keys)));

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

הפיתרון הוא פשוט ומופיע בתיעוד של JSON.stringify. הפרמטר השני לפונקציה נקרא replacer ותפקידו לעזור לנו לבחור איזה מפתחות להכניס ל JSON ומה יהיה הסדר שלהם. שימו לב:

> JSON.stringify({ a: 10, b: 20 }, ['a', 'b'] )
'{"a":10,"b":20}'
> JSON.stringify({ a: 10, b: 20 }, ['b', 'a'] )
'{"b":20,"a":10}'
> JSON.stringify({ a: 10, b: 20 }, ['b'] )
'{"b":20}'

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

const groups = _.groupBy(data, obj => JSON.stringify(_.pick(obj, keys), keys));