# traverse_dict

Definition: | traverse_dict(integer rid, object user_data=0, integer tid=1, bool rev=false)
Description: | Perform an in-order traversal of the dictionary, invoking the specified routine for each {key,data} pairing. rid: routine_id of a function that accepts three parameters, called for each entry. user_data: any additional data that might be required by rid. tid: a result from new_dict(), or if omitted it uses the one common dictionary. rev: when true, the traversal is made from the highest key to the lowest key.
pwa/p2js: | Supported.
Comments: | The specified routine should be a function that accepts three parameters: key, data, and user_data, and should return 1 to continue the traversal, or 0 to terminate it. Obviously modifying the key structure of tid during rid is likely to have unintended consequences (updating the data should however be fine). If you are traversing a complex tree structure and rebalance it underfoot, then anything can happen, from skipping whole subtrees, traversing them twice, or a fatal error. However it would be acceptable to terminate and restart the traversal after performing each key update (return 0), that is assuming you can skip any already-done updates on the next traversal. The ordering is case-sensitive. If a case-insensitive ordering is required, the key values as passed to setd() [etc] should be passed through either upper() or lower() and if needs be a copy of the original case included somewhere in data. The use of a named parameter when setting the rev flag is recommended, to make the intent clear and the code easier to read.
Example 1: |
    function visitor(object key, object data, object /*user_data*/)
        ?{key,data}
        return 1
    end function

    setd("key","data")
    setd("key2","data2")

    traverse_dict(routine_id("visitor"))
Example 2: |
    constant map1 = new_dict({{"key1","data1"}}),
             map2 = new_dict({{"key2","data2"}}),
             map3 = new_dict(map1)

    function merge(object key, object data, integer map3)
        setd(key,data,map3)
        return 1
    end function
    traverse_dict(routine_id("merge"),map3,map2)

    include builtins\map.e
    ?{"map1:",pairs(map1)}
    ?{"map2:",pairs(map2)}
    ?{"map3:",pairs(map3)}
    -- output
    -- {"map1:",{{"key1","data1"}}}
    -- {"map2:",{{"key2","data2"}}}
    -- {"map3:",{{"key1","data1"},{"key2","data2"}}}
Obviously should the same key occur in map1 and map2, the data from map2 will overwrite the corresponding map1 value. Note that other forms of merge are possible/may be required, for example if key is file size and data is a list of files of that size, the merge operation would probably want to concatenate the values from matching keys rather than replace them, eg:
    constant map1 = new_dict({{1234,{"this.txt"}}}),
             map2 = new_dict({{1234,{"that.txt"}}}),
             map3 = new_dict(map1)

    function merge(object key, object data, integer map3)
        integer node = getd_index(key,map3)
        if node=NULL then
            setd(key,data,map3)
            -- (possibly return 0 as per comment above)
        else
            setd(key,getd_by_index(node,map3)&data,map3)
        end if
        return 1
    end function
    traverse_dict(routine_id("merge"),map3,map2)
    include builtins\map.e
    ?{"map1:",pairs(map1)}
    ?{"map2:",pairs(map2)}
    ?{"map3:",pairs(map3)}
    -- output
    -- {"map1:",{{1234,{"this.txt"}}}}
    -- {"map2:",{{1234,{"that.txt"}}}}
    -- {"map3:",{{1234,{"this.txt","that.txt"}}}}
See Also: | setd, upper, lower, routine_id, traverse_dict_partial_key