Re: associated lists
- Posted by Jiri Babor <jbabor at PARADISE.NET.NZ> Aug 03, 2002
- 487 views
Kat, I am not sure which version you were referring to, but if it's the last 'official' release in the archives, about two years old, it had not two, but three versions, based on the same 'parallel' lists theme: standard, using find for shorter lists (up to several hundred items), sorted, using binary search for longer lists, and a hybrid with the cross-over point at 100 items. I have not done any tests recently; at the time I tried 7 or 8 different schemes (just from memory, some sort of comparison was included in the original package), and the 'parallel lists' scheme was clearly superior. But, as you well know, Euphoria is a bit of a moveable feast: Rob adds some new optimisations to almost every version. Also processor characteristics change a lot over time, so a bench mark that was quite reasonable yesterday possibly does not make much sense today. The trouble with the scheme you are suggesting is that you still have to 'unify' the two halves under a common label. And as far as indexing, fetching, setting and inserting operations are concerned, the corresponding functions (and they have to be functions, because Rob would not give us parameter passing by reference!:)), the two-level sequence does not seem to be much of a handicap. Just as a curiosity, I am including a simplified version I am currently using. You will notice, the nomenclature has changed a bit, but essentially it the same beast as the one in the archives. jiri >Jiri, in your associated lists, both versions seem to be "parallel" >lists of {{name},{value}}. Why not two separate lists of {name} and >{value}? Wouldn't find()ing be faster with a split system, with it's >inherently shorter sequences? >Courious as a, >Kat -- tables.e : tables | dictionaries | associative lists -- jiri babor -- jbabor at paradise.net.nz -- 2 August 2002 -- version 3.00 ---------------------------------------------------------------- -- 'parallel sequence' scheme: {{key1, ..kN}, {val1, ..valN}} ---------------------------------------------------------------- -- without warning -- without type_check global constant EMPTY = {{},{}} -- empty table global function index(sequence table, object key) -- return *key* index, or zero if key not found return find(key, table[1]) end function global function fetch(sequence table, object key) -- return table item with indicated key return table[2][find(key, table[1])] end function -- fetch global function set(sequence table, object key, object new_value) -- replace specified table item with a new value -- return modified table table[2][find(key, table[1])] = new_value return table end function -- set global function insert(sequence table, object key, object val) -- add new entry table[1] = append(table[1], key) table[2] = append(table[2], val) return table end function global function store(sequence table, object key, object val) -- store val in table under given key -- if matching key is found, corresponding value is replaced -- otherwise new key as well as value are appended -- return modified table integer i i = find(key, table[1]) -- key index if i then table[2][i] = val else table[1] = append(table[1], key) table[2] = append(table[2], val) end if return table end function -- store global function join(sequence table1, sequence table2) -- concatenate table1 and table2 return {table1[1] & table2[1], table1[2] & table2[2]} end function global function delete(sequence s, object key) -- delete entry with the specified key from the table s sequence s1,s2 integer i,m s1 = s[1] s2 = s[2] i = find(key, s1) -- index m = length(s1) return {s1[1..i-1]&s1[i+1..m], s2[1..i-1]&s2[i+1..m]} end function -- delete global function sort_table(sequence s) -- shell sort table s by keys in ascending order object t1i,t1j,t2i,t2j -- temporary objects sequence s1,s2 integer gap, j, first, last s1 = s[1] s2 = s[2] last = length(s1) gap = floor(last / 3) + 1 while 1 do first = gap + 1 for i = first to last do t1i = s1[i] t2i = s2[i] j = i - gap while 1 do t1j = s1[j] t2j = s2[j] if compare(t1i, t1j) >= 0 then j += gap exit end if s1[j+gap] = t1j s2[j+gap] = t2j if j <= gap then exit end if j -= gap end while s1[j] = t1i s2[j] = t2i end for if gap = 1 then return {s1,s2} else gap = floor(gap / 3) + 1 end if end while end function -- sort_table global function Fetch(object table, sequence keys) -- return item from *nested* table : 'deep' fetch for i = 1 to length(keys) do table = fetch(table, keys[i]) end for return table end function -- Fetch global function Set(sequence table, sequence keys, object new_value) -- 'deep', recursive set for *nested* tables integer i,m m = length(keys) i = find(keys[1],table[1]) if m = 1 then table[2][i] = new_value else table[2][i] = Set(table[2][i], keys[2..m], new_value) end if return table end function -- Set global function Insert(sequence table, sequence keys, object new_val) -- 'deep', recursive insert for nested tables -- store new_val in table under new (last) key in keys sequence -- return modified table integer i,n n = length(keys) if n = 1 then table[1] = append(table[1], keys[1]) table[2] = append(table[2], new_val) else i = find(keys[1], table[1]) -- key index table[2][i] = Insert(table[2][i], keys[2..n], new_val) end if return table end function global function Store(sequence table, sequence keys, object val) -- 'deep', recursive store for *nested* tables -- store val in table under last key in keys sequence -- return modified table integer i,n i = find(keys[1], table[1]) -- key index n = length(keys) if n = 1 then if i then table[2][i] = val else table[1] = append(table[1], keys[1]) table[2] = append(table[2], val) end if else table[2][i] = Store(table[2][i], keys[2..n], val) end if return table end function -- Store