## [REBOL] Re: Bidirectional value mapping.

### From: joel:neely:fedex at: 3-Nov-2003 12:56

Hi, Bruno, I know of no way to avoid some duplication. See below. Bruno G. Albuquerque wrote:> I have 2 values that would be mapped to each other. What I need to do is > to be able to find the first valeu by searching for the ceond and locate > the second by searching for the first. I did come up with solutions to > that but I am not satisfied with any of the solutions. Is there a standard > Rebol-Way ofr doing that? The best option would be a way that would not > result in data duplication. >The answer somewhat depends on details of your problem; if "forward" and "reverse" mappings are distinct (as in translating between host names and IP addresses, or encoding and decoding with a non-symmetric encryption scheme) then the simplest thing to do is keep both maps as separate blocks (or hashes):>> roman2number: ["i" 1 "v" 5 "x" 10 "l" 50 "c" 100]== ["i" 1 "v" 5 "x" 10 "l" 50 "c" 100]>> number2roman: [1 "i" 5 "v" 10 "x" 50 "l" 100 "c"]== [1 "i" 5 "v" 10 "x" 50 "l" 100 "c"]>> select roman2number "x"== 10>> select number2roman 10== "x" If you know which "way" you're mapping, you just select the appropriate map. (Of course, it's easy to write a function that would take one of the above and give the other, so you don't have to create both by hand.) NOTE!!! That last sentence is only true if the mapping is an invertable function!!! If, instead, you have a many-to-one (e.g. letters to the words "consonant" or "vowel") of course there's no way to invert. I assume you know that, but want to include that warning for completeness. The other (perhaps slightly more "REBOLish") way to do this is to inter- leave the forward and reverse mapping values as follows:>> roman-numerals: ["i" 1 "i" "v" 5 "v" "x" 10 "x" "l" 50 "l" "c" 100 "c" ] == ["i" 1 "i" "v" 5 "v" "x" 10 "x" "l" 50 "l" "c" 100 "c"]>> select roman-numerals "x"== 10>> select roman-numerals 10== "x" This works nicely for such things as ROT13, which is a self-inverse mapping (and again, you can write a utility function that would take e.g. ROMAN2NUMBER above and give you the interleaved ROMAN-NUMERALS). However THIS DOES NOT WORK IN GENERAL if the domain and range of your mapping overlap. As a simple example, consider the trivial example of rotating among three elements: forward: ["a" "b" "c" "a"] reverse: ["c" "b" "a" "c"] Since "a" maps to "b" going forward, but "b" maps to "c" going forward, then both forward and reverse mappings can't be combined into a single block/hash. To see why this is true, consider what would have to follow b in the combined series! Unless you know you have a self-inverse mapping and you consider speed soooooo important that you'll sacrifice readability for performance, I recommend using distinct forward/reverse mappings (with a helper to construct the inverted one). It'll be easier to read anyway! -jn- -- ---------------------------------------------------------------------- Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446 Enron Accountingg in a Nutshell: 1c=$0.01=($0.10)**2=(10c)**2=100c=$1