Expand/Shrink

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