תרגיל: עיגול מספר לפי מערך מפתחות
-
@dovid אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
אם הנקודה היא יעילות, יש פתרון יותר יעיל גם בלא ממויין.
מה הפתרון? אני ישמח לראות.
אם הנקודה היא יצירתיות שמופיעה בדבריך לסירוגין, אני לא יודע על מדד מוסכם לעניין אז קשה לדון מה הכי יצירתי.
הנקודה היא היעילות (הכי יעיל והכי קצר) והדרך להגיע לזה זה עם יצירתיות.
-
@קומפיונט אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
הכי יעיל והכי קצר
כל פעם אתה מוסיף ליעילות מילים שמטשטשות את התרגיל... קצר זה בקוד או בדרך שהמחשב יבצע? יעילות זה יעילות, לא צריך לפרשן את זה. קוד קצר זה נפלא אבל קשה למצוא ציון מתאים לשילוב בין שני הדברים האלה.
-
@dovid אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
כל פעם אתה מוסיף ליעילות מילים שמטשטשות את התרגיל... קצר זה בקוד או בדרך שהמחשב יבצע?
יעיל: לחסוך במשאבים, לדוג' לא לבצע תרגילים כפולים (יש לי כמה פתרונות שנכתבים בשורה אחת אבל עם תרגילים שמתבצעים פעמיים)
קצר: קוד הכי קצר שאפשר.
-
@קומפיונט אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
מעניין אותי אם תכתוב לנו את הפתרון מתי שהוא?
למה לא תחכים אותנו?!א. אני גם תהיתי אם יום אחד תכתוב לנו את הקוד בו סרקת תוך שניות את הקוד ההוא של המודלו...
ב. אני מבטיח לענות תוך שבוע... ממה שאני מכיר פה יהיה כאלו שיעלו על חולשת הMinBy לפני שאענה. שים לב שההצעה שלי לא יותר קצרה, ושים לב שלבקש קוד הכי קצר והכי יעיל זה כמו לבקש מכונית הכי מהירה ועם הכי הרבה מקום בו זמנית בלי להסביר לפי מה יחולק הציון בין שני הפרמטרים. -
@dovid אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
א. אני גם תהיתי אם יום אחד תכתוב לנו את הקוד בו סרקת תוך שניות את הקוד ההוא של המודלו...
אין לי משהו מיוחד בקוד, זה brute force פשוט. העניין הוא מאיזה מספר להתחיל את הסריקה. לא התחלתי מאפס, כמובן.
שים לב שההצעה שלי לא יותר קצרה, ושים לב שלבקש קוד הכי קצר והכי יעיל זה כמו לבקש מכונית הכי מהירה ועם הכי הרבה מקום בו זמנית בלי להסביר לפי מה יחולק הציון בין שני הפרמטרים.
אם יש לך אחד משני הפרמטרים שהוא יותר טוב זה מספיק לי.
כולנו לעיתים כותבים קוד יותר קריא מאשר מהיר מבחינת ביצועים. (מי מאתנו לא משתמש ב-LINQ? זה ודאי יותר איטי מלולאה) אז צריך לבחור בצורה הגיונית מה עדיף, ואני לא צריך לתת ציונים מפורשים איזה פרמטר אני מעדיף. לך לפי השכל הישר. (אם יש לי קוד קצר כנגד קוד מאוד מסורבל אבל קצת יותר מהיר, אז אני אעדיף את הקוד הקצר, לעומת זאת אם יש לי קוד קצר איטי כנגד קוד יותר ארוך אבל יותר מהיר משמעותית אז אני יבחר את הקוד הארוך, ובפרט אם זה קוד שמתבצע הרבה פעמים, ולא רק פה ושם).אתה יודע מה, שורה תחתונה - אני מעוניין בקוד הכי קצר שאפשר.
-
@קומפיונט אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
יש לי מערך של מפתחות, לדוג 100 200 300 ... ואני רוצה שהמשתמש יזין מספר כלשהו הוא יעוגל למספר המפתח הקרוב ביותר.
יש לי כמה דרכים לעשות את זה, אבל אני מחפש את הדרך הכי קצרה ויעילה.
אולי יש למשהו דרך יצירתית לעשות את זה?
יש לציין שהפתרון שלי הוא רק בשפות של NET., אבל בטוח יש דרכים יצירתיות גם בשפות אחרות. אז אתם גם מוזמנים לנסות (כמובן בלי גוגל).
בלי לחפש...
הפתרון כאן הוא ב VBA.
אני מניח שכל המערך הוא עם ערכי INT בלבד,
וגודל המערך ידוע, אך גודלו יכול להיות LONG.והדרך הכי יעילה מבחינתי, זה לקודד לבד... כך כל פעולה ידועה,
והכי קצרה - לכתוב את זה כפונקציה:)נ.ב. יכול להיות שיש עוד דרכים יותר טובות - לא בדקתי את הקודים בשרשור.
וגם - יש משהו מעצבן בVBA, שבחלק מהיישומים (לדוגמה, אצלי) א"א לדעת את גבולות המערך למרות שיש פונקציה ייעודית לזה (LowerBound, ו UpperBound) וכש"כ לא את גודל המערך, לכן הוספתי פרמטרים של גבולות המערך.Option Explicit Public Function Round(ByRef Value As Integer, ByRef Arr() As Integer, ByRef Length As Long, Optional ByRef LowerBound As Long = 0) As Integer Dim i As Long Dim lower As Integer, upper As Integer If Value = Arr(LowerBound) Then Round = Value Exit Function ElseIf Arr(LowerBound) > Value And Arr(LowerBound) < 32767 Then ' limit intreger == 32767 upper = Arr(LowerBound) ElseIf Arr(LowerBound) < Value And Arr(LowerBound) > lower Then upper = 32767 lower = Arr(LowerBound) End If For i = LowerBound + 1 To LowerBound + Length - 1 If Value = Arr(i) Then Round = Value Exit Function ElseIf Arr(i) > Value And Arr(i) < upper Then upper = Arr(i) ElseIf Arr(i) < Value And Arr(i) > lower Then lower = Arr(i) End If 'Debug.Print "arr(i) " & Arr(i) & " lower " & lower & " upper " & upper Next i If upper - Value <= Value - lower Then Round = upper Else Round = lower End Function Sub בדיקה() Dim AA(1 To 5) As Integer AA(1) = 4 AA(2) = 12 AA(3) = 2 AA(4) = 22 AA(5) = 80 MsgBox Round(CInt(InputBox("")), AA, 5, 1) End Sub
-
@Y-Excel-Access יפה מאוד!
אני חושב שאתה יכול בדרך שלך לחסוך את ההקדמה ללולאה:Dim i As Long Dim lower As Integer, upper As Integer lower = -32768 upper = 32767 For i = LowerBound To LowerBound + (Length - 1) If Value = Arr(i) Then Round = Value Exit Function ElseIf Arr(i) > Value And Arr(i) < upper Then upper = Arr(i) ElseIf Arr(i) < Value And Arr(i) > lower Then lower = Arr(i) End If Next i If upper - Value <= Value - lower Then Round = upper Else Round = lower
@Y-Excel-Access אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
וגם - יש משהו מעצבן בVBA, שבחלק מהיישומים (לדוגמה, אצלי) א"א לדעת את גבולות המערך למרות שיש פונקציה ייעודית לזה (LowerBound, ו UpperBound) וכש"כ לא את גודל המערך, לכן הוספתי פרמטרים של גבולות המערך.
מה הכונה א"א? מה הפונקציות UBound/LBound מחזירים? באיזה יישומים מדובר?
בכל מקרה לולאת for each חוסכת את כל העצבים של מעבר על לולאה, וככה נחסכת לך גם בעיית הגבולות:
Public Function Round(ByRef Value As Integer, ByRef Arr() As Integer) As Integer Dim lower As Integer, upper As Integer lower = -32768 upper = 32767 For Each Item In Arr ' Iterate through each element. If Value = Item Then Round = Value Exit Function ElseIf Item > Value And Item < upper Then upper = Item ElseIf Item < Value And Item > lower Then lower = Item End If Next If upper - Value <= Value - lower Then Round = upper Else Round = lower End Function
בכל מקרה חשיבה קוד יפים!
-
במקרה בו הרווחים קבועים וידועים, יש פתרון פשוט בלי לעבור על המערך כלל
לדוגמה:
const int INTERVAL = 100; int[] keys = Enumerable.Range(1, 9).Select(v => v * INTERVAL).ToArray(); // 100 200 300 ... int input = new Random().Next(1000); int mod = input % INTERVAL; int rounded = Math.Clamp((input - mod) + ((mod > INTERVAL / 2) ? INTERVAL : 0), keys[0], keys[keys.Length - 1]);
-
@Y-Excel-Access יפה מאוד. אני לא בקיא ב-vb אז קצת קשה לי להבין את כל הקוד שכתבת. אבל מבדיקה מהירה שלי ראיתי שאם אני מכניס מספר יותר גבוה מהמספר המקסימאלי אז נזרקת שגיאה.
אגב, הקוד נראה לי קצת ארוך... אז בשביל התרגיל תנסה לקצר אותו כמה שאפשר, אני רואה ש@dovid כבר קיצר לך קצת.
-
@קומפיונט אני נותן רמז, שהפתרון של @Y-Excel-Access מממש את ההבדל עליו דיברתי שיהיה יעיל יותר מהMaxBy.
הנה הקוד של @Y-Excel-Access אבל עם שימוש בMath.Abs:
Public Function Round(ByRef Value As Integer, ByRef Arr() As Integer) As Integer Dim temp As Integer, diff As Integer, fit As Integer diff = 32767 For Each Item In Arr ' Iterate through each element. If Value = Item Then Round = Value Exit Function Else temp = Math.Abs(Value - Item) 'Math.Abs turn minus and plus to plus. If temp < diff Then diff = temp fit = Item End If End If Next Round = fit End Function
-
@dovid אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
@קומפיונט אמר בתרגיל: עיגול מספר לפי מערך מפתחות:
אגב, אפשר לכתוב keys[^1] במקום keys[keys.Length - 1]
הגיוני בפורום לכתוב באופן שכל אחד יכול לבדוק בלי לציין שמדובר בגריסה מאוד חדשנית.
בפרט בקוד רעיוני/תרגיל.סליחה, בכל מקום שMath.Clamp יעבוד (CORE 2 ומעלה) זה בהכרח C# 7.3 לפחות.