How to resolve the algorithm Range expansion step by step in the AppleScript programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Range expansion step by step in the AppleScript programming language

Table of Contents

Problem Statement

A format for expressing an ordered list of integers is to use a comma separated list of either Example The list of integers: Is accurately expressed by the range expression: (And vice-versa).

Expand the range description: Note that the second element above, is the range from minus 3 to minus 1.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Range expansion step by step in the AppleScript programming language

Source code in the applescript programming language

-- Each comma-delimited string is mapped to a list of integers,
-- and these integer lists are concatenated together into a single list


---------------------- RANGE EXPANSION ---------------------

-- expansion :: String -> [Int]
on expansion(strExpr)
    -- The string (between commas) is split on hyphens, 
    -- and this segmentation is rewritten to ranges or minus signs
    -- and evaluated to lists of integer values
    
    -- signedRange :: String -> [Int]
    script signedRange
        -- After the first character, numbers preceded by an
        -- empty string (resulting from splitting on hyphens)
        -- and interpreted as negative
        
        -- signedIntegerAppended:: [Int] -> String -> Int -> [Int] -> [Int]
        on signedIntegerAppended(acc, strNum, iPosn, xs)
            if strNum  "" then
                if iPosn > 1 then
                    set strSign to |λ|(0 < length of (item (iPosn - 1) of xs)) ¬
                        of bool("", "-")
                else
                    set strSign to "+"
                end if
                
                acc & ((strSign & strNum) as integer)
            else
                acc
            end if
        end signedIntegerAppended
        
        on |λ|(strHyphenated)
            tupleRange(foldl(signedIntegerAppended, {}, ¬
                splitOn("-", strHyphenated)))
        end |λ|
    end script
    
    concatMap(signedRange, splitOn(",", strExpr))
end expansion


---------------------------- TEST --------------------------
on run
    
    expansion("-6,-3--1,3-5,7-11,14,15,17-20")
    
    --> {-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}
end run


--------------------- GENERIC FUNCTIONS --------------------


-- bool :: a -> a -> Bool -> a
on bool(tf, ff)
    -- The evaluation of either tf or ff, 
    -- depending on a boolean value.
    script
        on |λ|(bln)
            if bln then
                set e to tf
            else
                set e to ff
            end if
            set c to class of e
            if {script, handler} contains c then
                |λ|() of mReturn(e)
            else
                e
            end if
        end |λ|
    end script
end bool

-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
    script append
        on |λ|(a, b)
            a & b
        end |λ|
    end script
    
    foldl(append, {}, map(f, xs))
end concatMap

-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
    if n < m then
        set d to -1
    else
        set d to 1
    end if
    set lst to {}
    repeat with i from m to n by d
        set end of lst to i
    end repeat
    return lst
end enumFromTo

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- splitOn :: Text -> Text -> [Text]
on splitOn(strDelim, strMain)
    set {dlm, my text item delimiters} to {my text item delimiters, strDelim}
    set xs to text items of strMain
    set my text item delimiters to dlm
    return xs
end splitOn

-- range :: (Int, Int) -> [Int]
on tupleRange(tuple)
    if tuple = {} then
        {}
    else if length of tuple > 1 then
        enumFromTo(item 1 of tuple, item 2 of tuple)
    else
        item 1 of tuple
    end if
end tupleRange


{-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}


on rangeExpansion(rangeExpression)
    -- Split the expression at the commas, if any.
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to ","
    set theRanges to rangeExpression's text items
    
    set integerList to {}
    set AppleScript's text item delimiters to "-"
    repeat with thisRange in theRanges
        -- Split each range or integer text at its dash(es), if any.
        set rangeParts to thisRange's text items
        -- A minus before the first integer will make leading text item "".
        -- If this happens, insert the negative first value at the beginning of the parts list.
        -- (AppleScript automatically coerces numeric text to number when the context demands.)
        if (rangeParts begins with "") then set beginning of rangeParts to -(item 2 of rangeParts)
        -- A minus before the second (or only) integer will make the penultimate text item "".
        -- In this case, insert the negative last value at the end of the parts list.        
        if (((count rangeParts) > 1) and (item -2 of rangeParts is "")) then set end of rangeParts to -(end of rangeParts)
        -- Append all the integers implied by the range to the integer list.
        repeat with i from (beginning of rangeParts) to (end of rangeParts)
            set end of integerList to i
        end repeat
    end repeat
    set AppleScript's text item delimiters to astid
    
    return integerList
end rangeExpansion

-- Demo code:
set rangeExpression to "-6,-3--1,3-5,7-11,14,15,17-20"
return rangeExpansion(rangeExpression)


{-6, -3, -2, -1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20}


  

You may also check:How to resolve the algorithm Modified random distribution step by step in the REXX programming language
You may also check:How to resolve the algorithm Pell's equation step by step in the Delphi programming language
You may also check:How to resolve the algorithm Longest increasing subsequence step by step in the Wren programming language
You may also check:How to resolve the algorithm Date manipulation step by step in the UNIX Shell programming language
You may also check:How to resolve the algorithm Program name step by step in the VBA programming language