Averages/Median: Difference between revisions
Content added Content deleted
No edit summary |
m (→{{header|AppleScript}}: Corrected "By iteration" solution, which was returning random results with even list counts. Tidied "Quickselect".) |
||
Line 191: | Line 191: | ||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
===By iteration=== |
===By iteration=== |
||
<lang |
<lang applescript>set alist to {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0} |
||
set med to medi(alist) |
set med to medi(alist) |
||
Line 200: | Line 198: | ||
set temp to {} |
set temp to {} |
||
set lcount to count |
set lcount to count alist |
||
if lcount is equal to 2 then |
if lcount is equal to 2 then |
||
return (item |
return ((item 1 of alist) + (item 2 of alist)) / 2 |
||
else if lcount is less than 2 then |
else if lcount is less than 2 then |
||
return item 1 of alist |
return item 1 of alist |
||
Line 238: | Line 236: | ||
end findmax</lang> |
end findmax</lang> |
||
{{output}} |
|||
<lang applescript>3.5</lang> |
|||
===Composing functionally=== |
===Composing functionally=== |
||
Line 355: | Line 356: | ||
===Quickselect=== |
===Quickselect=== |
||
<lang applescript>-- Return the median value of items l thru r of a list of numbers. |
|||
on getMedian(theList, l, r) |
|||
if (theList is {}) then return theList |
if (theList is {}) then return theList |
||
-- A local "owner" for the potentially long AppleScript list. Speeds up references to its items and properties. |
|||
script o |
script o |
||
property lst : theList |
property lst : theList's items l thru r -- Copy of the range to be searched. |
||
end script |
end script |
||
-- But since sorting's involved, use another list containing the same items. |
|||
set o's lst to o's lst's items |
|||
set |
set rangeLength to (r - l + 1) |
||
set m to ( |
set m to (rangeLength + 1) div 2 -- Central position in the range copy, or the leftmost of two. |
||
set {l, r} to {1, rangeLength} -- Outer partition indices. |
|||
⚫ | |||
-- The initial search process is an iterative quickselect: ie. a partial, iterative quicksort (algorithm by Tony Hoare) with subpartitioning only occurring in partitions containing m. |
|||
⚫ | |||
-- It stops when the partition traversal indices cross at m, which means that slot m now contains the median value or the leftmost of two. |
|||
-- If the number of items in the list is even, a straight sweep is then done for the lowest value partitioned to the right of m and the two results are averaged. |
|||
set l to 1 |
|||
set r to listLength |
|||
⚫ | |||
⚫ | |||
set pivot to o's lst's item ((l + r) div 2) |
set pivot to o's lst's item ((l + r) div 2) |
||
set i to l |
set i to l |
||
set j to r |
set j to r |
||
repeat until (i > j) |
repeat until (i > j) |
||
set |
set lv to o's lst's item i |
||
repeat while ( |
repeat while (lv < pivot) |
||
set i to i + 1 |
set i to i + 1 |
||
set |
set lv to o's lst's item i |
||
end repeat |
end repeat |
||
set |
set rv to o's lst's item j |
||
repeat while ( |
repeat while (rv > pivot) |
||
set j to j - 1 |
set j to j - 1 |
||
set |
set rv to o's lst's item j |
||
end repeat |
end repeat |
||
if (i > j) then |
if (i > j) then |
||
else |
else |
||
set o's lst's item i to |
set o's lst's item i to rv |
||
set o's lst's item j to |
set o's lst's item j to lv |
||
set i to i + 1 |
set i to i + 1 |
||
set j to j - 1 |
set j to j - 1 |
||
Line 400: | Line 394: | ||
end repeat |
end repeat |
||
-- |
-- If i and j have crossed at m, item m's the median value. |
||
-- Otherwise reset to partition the partition containing m. |
|||
if (j < m) then |
if (j < m) then |
||
-- If they crossed at m, it now contains the median value or the leftmost of two, so finish the quickselect. |
|||
if (i > m) then exit repeat |
if (i > m) then exit repeat |
||
-- Otherwise they crossed to the left of m. Prepare to subpartition the right partition. |
|||
set l to i |
set l to i |
||
else |
else |
||
-- They crossed to the right of m. Prepare to subpartition the left, but keep a note of the current right boundary in case it's needed below. |
|||
set previousR to r |
set previousR to r |
||
set r to j |
set r to j |
||
end if |
end if |
||
end repeat |
end repeat |
||
set median to item m of o's lst |
set median to item m of o's lst |
||
-- If the |
-- If the range has an even number of items, find the lowest value to the right of m and average it |
||
-- with the median just obtained. We only need to search to the end of the range just partitioned — |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
if (r = m) then set r to previousR |
if (r = m) then set r to previousR |
||
repeat with i from ( |
repeat with i from (i + 1) to r |
||
set |
set v to item i of o's lst |
||
if ( |
if (v < median2) then set median2 to v |
||
end repeat |
end repeat |
||
set median to (median + median2) / 2 |
set median to (median + median2) / 2 |
||
Line 430: | Line 423: | ||
-- Demo: |
-- Demo: |
||
local testList |
|||
set testList to {} |
set testList to {} |
||
repeat with i from 1 to 8 |
repeat with i from 1 to 8 |
||
set end of |
set end of testList to (random number 500) / 5 |
||
end repeat |
end repeat |
||
⚫ | |||
set m to getMedian(testList) |
|||
⚫ | |||
{{output}} |
{{output}} |