When writing a message with fridge magnets, you'll often find yourself substituting a 1 for an I. In this challenge, your goal is to find out if a message can be written using the letters of another message. The allowed substitutions are:

A = 4
B = 8
C = U
E = M = W = 3
G = 6 = 9
I = 1
L = 7
N = Z
O = 0
R = 2
S = 5

For example, the message CIRCA 333 can be rearranged to spell ICE CREAM, where the first two 3s are rotated 180 degrees to make two Es, and the last 3 is rotated 90 degrees counterclockwise to make an M. Whitespaces can be included in the messages, but they should not be accounted for in your solution, as they're made by placing the magnets on the fridge.


Two strings (or character arrays). All messages will match ^[A-Z0-9 ]+$


Truthy if the two input strings are valid rearrangements of each other, falsey otherwise.


["CIRCA 333", "ICE CREAM"] => true
["DCLV 00133", "I LOVE CODE"] => true
["WE ARE EMISSARIES", "33   423    3315542135"] => true
["WE WANT ICE CREAM", "MET CIRCA 334 MEN"] => true

More thruthy examples

These are all the 15+ letter words that map to another word. Some are trivial substitutions, but I included all that I found.


As this is a code golf challenge, the shortest solution wins! I will accept the shortest solution in 7 days from posting. Happy golfing!

Sample solution, non-golfed


EDIT: Made an error in the substitutions, had G = 6 and 6 = 9 as separate substitutions, merged them into one.

  • 2
    \$\begingroup\$ I think 48 hours is a bit short. What about people who only golf on weekends? \$\endgroup\$
    – Adám
    Commented May 15, 2018 at 7:49
  • \$\begingroup\$ Good point, I'll give it a week. \$\endgroup\$
    – maxb
    Commented May 15, 2018 at 7:57
  • 1
    \$\begingroup\$ Other substitutions that you might consider allowing are 7 for T, H for I (but not 1 for H), and 2 for N or Z \$\endgroup\$ Commented May 15, 2018 at 11:39
  • 1
    \$\begingroup\$ @JeffZeitlin We had a discussion about this in the challenge sandbox, and I chose to exclude all substitutions which are not reversible. Since T and L are not exchangeable, I can't add T = 7. The same goes for N = Z = 2, which would imply that N = Z = R = 2. However, the kind of substitutions you suggest would make for a more difficult version of this challenge, which I might post at a later time. I just wanted to see if these kinds of challenges would be well received first. \$\endgroup\$
    – maxb
    Commented May 15, 2018 at 11:55
  • 1
    \$\begingroup\$ @3D1T0R yes, the substitution must go both ways. The check is if two strings are valid rearrangements of each other. Your example would return false. \$\endgroup\$
    – maxb
    Commented May 15, 2018 at 17:53

15 Answers 15


Python 2, 145 131 130 129 125 bytes

lambda*a:all(len({sum(map(w.count,x))for w in a})<2for x in'A4 B8 CU EMW3 G69 I1 L7 NZ O0 R2 S5'.split()+list('DFHJKPQTVXY'))

Try it online!


Python 2, 125 bytes

lambda*a:len({(x,sum(map(w.count,x)))for x in'A4 B8 CU EMW3 G69 I1 L7 NZ O0 R2 S5'.split()+list('DFHJKPQTVXY')for w in a})<23

Try it online!


Ruby, 99 72 71 bytes

->a{!!a.map{|x|x.tr("0-9UZMW","OIREASGLBGCNE").chars.sort-[" "]}.uniq!}

Try it online!

Takes an array of strings, assumes input in uppercase as in all test cases.

-1 byte golfed by benj2240.


JavaScript (ES6), 102 100 bytes

Takes input as two arrays of characters in currying syntax (a)(b). Returns a boolean.


Try it online!


Using the helper function g(), for each input s:

  • Digits 0 to 8 and letters X, Y and Z are left unchanged. Everything else is explicitly translated.



    s.map(c => '648UD3F6H1JK73Z0PQ25TUV3'[parseInt(c, 36) - 9] || c)
  • We sort the characters (which brings all spaces at the beginning), join them and remove all leading whitespace.



Finally, we compare both outputs.


Retina 0.8.2, 42 bytes


Try it online! Takes input on separate lines, but Link includes test cases and header. Explanation:


Map all the letters to a minimal set, deleting the spaces.


Sort each string into order.


Compare the two values.


APL (Dyalog Unicode), 49 bytesSBCS

-1 thanks to ngn.

Anonymous tacit prefix function.

(≡/(⍋⌷¨⊂)¨)(,¨⎕D,'UMWZ ')⎕R('OIREASGLBGCEEN',⊂⍬)

Try it online!

⎕R PCRE Replace:
'UMWZ ' these five characters
⎕D, preceded by the digits
 separately (make each into a string rather than being a single character)
⊂⍬ nothing
'OIREASGLBGCEEN', preceded by these characters

() apply the following tacit function to that:

( apply the following tacit function to each:

   enclose it (to treat it as a whole)

  ⍋⌷¨ use each of the indices that would sort it to index into the whole string (sorts)

≡/ are they identical? (lit. match reduction)

  • \$\begingroup\$ '' -> ­­­­ \$\endgroup\$
    – ngn
    Commented May 15, 2018 at 19:51
  • \$\begingroup\$ @ngn Not sure why that works, but thanks anyway. \$\endgroup\$
    – Adám
    Commented May 15, 2018 at 20:33

Python 2, 108 bytes

lambda a,b:g(a)==g(b)
g=lambda s:sorted('85930A4614012B3C4D5EF6378GH9AI2J3KL7'[int(c,36)]for c in s if'!'<c)

Try it online!

There are 23 equivalence classes of characters. Using the 36-character string '85930A4614012B3C4D5EF6378GH9AI2J3KL7', we map each character to its equivalence class (ignoring spaces), then sort the resulting array. Two strings are equivalent iff the resulting lists are equal.


Japt, 38 36 33 30 bytes

Takes input as an array of 2 strings.

®d`z³m`i`oiglbg`í)Ôu)ñ xÃr¶

Try it or run all test cases

3 bytes saved thanks to ETHProductions

®d`z...m`i`o...g`í)Ôu)ñ xÃr¶
                                 :Implicit input of array U
®                                :Map each Z
 d                               :  For each pair of characters in the following string,
                                 :  replace all occurrences of the 1st character in Z with the 2nd
  `z...m`                        :    The compressed string "znewem"
         i                       :    Prepend
          `o...g`                :      The compressed string "oireasglbg"
                 í               :      Interleave 0-based indices
                  )              :    End prepend
                   Ô             :    Reverse
                    u            :    Convert to uppercase
                     )           :  End replace
                      ñ          :  Sort
                        x        :  Trim
                         Ã       :End map
                          r      :Reduce
                           ¶     :  By testing equality
  • \$\begingroup\$ Nice, currently beating Jelly! I think you can do at the end to save 3 bytes. \$\endgroup\$ Commented May 16, 2018 at 4:45
  • \$\begingroup\$ Oh, yeah, I was forgetting that. Thanks, @ETHproductions. \$\endgroup\$
    – Shaggy
    Commented May 16, 2018 at 8:42

Java 10, 262 260 258 216 208 174 bytes

a->b->n(a).equals(n(b));String n(String s){return s.chars().mapToObj(x->x<48?"":"OIREASGLBG.......ABCDEFGHIJKLENOPQRSTCVEXYN".split("")[x-48]).sorted().reduce("",(a,b)->a+b);}

-2 bytes thanks to @Arnauld.
-76 bytes thanks to @OlivierGrégoire.

Try it online.


a->b->                      // Method with two String parameters and boolean return-type
  n(a).equals(n(b))         //  Return if both Strings are equal in the end

String n(String s){         // Separated method with String as both parameter return-type
  return s.chars()          //  Loop over all characters as integers
          .mapToObj(x->x<48?//   If the current character is a space:
             ""             //    Replace it with an empty String to skip it
            :               //   Else:
                            //    Convert multi-substitution characters to a single one
          .sorted()         //  Sort all of the converted characters
                            //  And join all of them together as single String
  • 2
    \$\begingroup\$ "A4B8CUEMEWE3G6G9I1L7NZO0R2S5".split("(?<=\\G.{2})") seems to work ... although I'm not even sure exactly how. :p \$\endgroup\$
    – Arnauld
    Commented May 15, 2018 at 17:42
  • \$\begingroup\$ @Arnauld Thanks, -2 bytes, and {2} can be . for another -2 bytes. I'm also not 100% sure how it works. I know (?<= ... ) is used to split but keep trailing delimiter per item. But I'm a bit confused why (?=\\G..) (keep leading delimiter) doesn't work in that regard. And also don't really know how the \\G.. vs .. acts in the split here. Will see if I can figure it out somewhere, because not I'm curious. ;p Thanks either way for the saved bytes. Need to remember \\G when splitting on even-sized blocks. :) \$\endgroup\$ Commented May 16, 2018 at 7:12
  • 1
    \$\begingroup\$ @Arnauld If you want some background about (?<=\\G..) inside a split, I've made a StackoverFlow question which shed some light. Basically it's undefined behavior working differently in almost every language. Although \G is zero-length, in Java with the positive look-behind inside the split, it kinda conflicts both rules causing the behavior we see here. It's still all a bit vague to me personally, but at least it saved 4 bytes in this answer. ;) \$\endgroup\$ Commented May 16, 2018 at 9:23
  • 1
    \$\begingroup\$ 217 bytes. Can save more bytes, though. \$\endgroup\$ Commented May 16, 2018 at 10:43
  • 1
    \$\begingroup\$ 174 bytes. \$\endgroup\$ Commented May 16, 2018 at 12:21

R, 123 bytes

function(x,y=chartr("48UMW36917Z025","ABCEEEGGILNORS",gsub(" ","",x)))all(g(y[1])==g(y[2]))

Try it online!

utf8ToInt converts a string into a vector of Unicode code points.

!sd(a-b) is one byte shorter than all(a==b) but that doesn't help here because I'm actually dealing with integers and not logicals.

  • \$\begingroup\$ Very nice! I think you need !any in place of !sd as the elements could be all equal, but to 1. Try: f(list("BCDEF","ABCDE")) \$\endgroup\$
    – JayCe
    Commented May 16, 2018 at 19:12

J, 56 bytes

-:&(-.&' '/:~@rplc'0123456789UMWZ';"0'OIREASGLBGCEEN'"1)

Try it online!


& for both left and right arguments

-.&' ' removes spaces from the input,

rplc replaces

'0123456789UMWZ';"0'OIREASGLBGCEEN'"1 the characters in the input by substitution of the chars in the left column with the ones in the right one: (here transposed for saving space)


/:~@ and sorts the resulting strings

-: are the sorted strings equal?

My initial solution:

J, 77 73 bytes

-:&(1#.(' '-.~])e."1[:(,a.,.@-.,)'EMW3','G69',9 2$'A4B8CUI1L7NZO0R2S5'"1)

Try it online!


(' '-.~]) removes spaces from both arguments and

e."1 tests each character for membership in the follwing table:

[:(,a.,.@-.,)'EMW3','G69',9 2$'A4B8CUI1L7NZO0R2S5'"1 the reference:

All other symbols one in a row

1#. adds up the comparison tables for each argument

-:& do they match?


Perl 6, 55 bytes

{[eq] .map:{sort TR/0..9UZMW/OIREASGLBGCNEE/~~m:g/\S/}}

Try it online!

Works with an arbitrary number of strings.


Python 2, 111 bytes

lambda*t:2>len({`sorted(s.translate(dict(map(None,map(ord,'48UMW36917Z025 '),u'ABCEEEGGILNORS'))))`for s in t})

Try it online!

116 bytes

lambda a,b:g(a)==g(b)
g=lambda s,y='4A8BUCMEWE3E6G9G1I7LZN0O2R5S ':y and g(s.replace(y[0],y[1:2]),y[2:])or sorted(s)

Try it online!


Python 3, 105 bytes

lambda a,b:X(a)==X(b)
X=lambda s:sorted(("ABCEEEGGILNORS"+c)["48UMW36917Z025".find(c)]for c in s if' '<c)

Try it online!


Jelly, 39 34 bytes


Try it online!


05AB1E, 38 33 bytes


Try it online or verify all test cases.


ε                   # Map each value in the (implicit) input-list by:
 ðK                 #  Remove all spaces
   .•2Θ`ĆĀÑεÉ•      #  Push compressed string "abemwgilorsuz"
              u     #  To uppercase: "ABEMWGILORSUZ"
               6«   #  Append a 6: "ABEMWGILORSUZ6"
   •B/óÕ¦•          #  Push compressed integer 48333917025
          …CN9«     #  Append "CN9": "48333917025CN9"
   ‡                #  Transliterate; map all characters in "ABEMWGILORSUZ" in the
                    #  map-string to "48333917025CN9" at the same indices
    {               #  Then sort all characters
}                   # Close the map
 Ë                  # And check if both are equal (which is output implicitly)

See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary? and How to compress large integers?) to understand why .•2Θ`ĆĀÑεÉ• is "abemwgilorsuz" and •B/óÕ¦• is 48333917025.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.