צלילה למנוע הביטויים של QGIS, חלק 9: שימוש בכל השדות

 

חבר שאל אותי לפני כמה ימים איך להוציא את הסכום של השדות בשכבה עם QGIS. הייתה לו שכבה שבה כל השדות היו מספריים והוא רצה לקבל את הסכום שלהם בדומה לפונקצייה dplyr::across של R.
זאת שאלה יחסית מעניינת, לא בגלל שזו בעיה נפוצה אלא בגלל שזה גרם לי לחשוב על איך שולפים בצורה אוטומטית את המידע משדות בשכבה של QGIS, משמע בלי לדעת את שמות השדות.

את הערכים של כל שדות השכבה אנחנו יכולים לשלוף עם ביטוי יחסית פשוט:

    map_avals( attributes( ))

 

 
מה שהוא עושה זו פשוט שליפה לתוך מערך של כל הערכים מהשכבה, אפשר לבדוק מה שמות וסדר השדות שהמערך מחזיר את הערך שלהם עם ביטוי די דומה:

    map_akeys( attributes( )) 
 

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

    1. array_filter - שנותנת לנו לסנן מערך רק לערכים הרלוונטיים
    2.to_real - שתנסה להמיר את כל הערכים במערך שלנו למספר
    3. try - שפשוט הולכת לנסות, כשמה כן היא, ותגיד לנו מתי ההמרות למספרים נכשלות בלי שהביטוי יכשל
 
אם נשלב את הביטוי המקורי שלנו עם הפונקציות האלו נוכל לקבל חזרה רק מערך עם ערכים מספריים
 
    array_filter(
        map_avals( attributes()),
        try( to_real( @element),false)
    )
 
 
 
אנחנו יכולים לעצור פה אם נעטוף את כל הביטוי הזה בarray_sum וככה נקבל את הסכום של כל הערכים המספריים שלנו. החיסרון של לעצור פה, הוא שאנחנו עדיין לא בדקנו האם כל איבר במערך הוא מספר, זה בגלל שהמערך שלנו לא כולל את הערכים שהיו שווים ל 0. זה בגלל שמנוע הביטויים קורא את הערך false כ0 ולהיפך (0 שווה לfalse), אז פונקציות סינון, מצפות לנכון\לא נכון (true\false) או 1\0 וקוראות אותן באותה צורה.
אם נניח שאנחנו רוצים להשתמש במערך מספרי לחישובים מלבד סכימה, כדאי שנעשה תיקון בביטוי כדי שהמערך שהוא מחזיר לנו יכלול גם אפסים. אז נעשה תיקון, אפילו תיקון יחסית פשוט, נוסיף בדיקה אם הערך שווה ל0 או אם אפשר להמיר אותו למספר. בגלל שהבדיקה האם הערך שווה ל0 היא יותר מוקדמת היא תחזיר לנו נכון (true) ונקבל במערך את כל האפסים שלנו.

array_filter(
    map_avals( attributes()),
    @element = 0 or try( to_real( @element),false)
)

לבסוף אנחנו יכולים לעטוף את הביטוי שלנו בפונקציית חישוב על פני מערך, סכימה במקרה הזה:
 
    array_sum(
        array_filter(
            map_avals( attributes()),
            @element = 0 or try( to_real( @element),false)
        )
    )


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

Exploring The QGIS Expression Engine, Part 1: Getting Values From JSON & HSTORE

Exploring The QGIS Expression Engine, Part 2: What's Missing From Select By Location 

Exploring The QGIS Expression Engine, Part 3: Writing Custom Expression Functions

Exploring The QGIS Expression Engine, Part 4: Selecting By Attributes And Location With One Expression

Exploring The QGIS Expression Engine, Part 5: Fun With Arrays

Exploring The QGIS Expression Engine, Part 6: Creating And Using Variables

Exploring The QGIS Expression Engine, Part 7: Cross-Layer Relationships 

Exploring The QGIS Expression Engine, Part 8: Expression Controlled Styles

Comments