# More efficient US state codes

Abbreviate that US state! was fun, but we learnt that efficiently abbreviating US state names is hard with the current system. Let's come up with an alternative state code scheme for efficient golfing.

Write a function (or program) which, given a valid US state name (only the 50 normal states required), returns a unique two-letter code in uppercase identifying it. The code must meet these requirements:

• The first letter must be the same as the first letter of the state.
• The second letter must be one of the other letters of the state (not a space).
• It must always give the same output for the same input, and must never give the same output for two different valid inputs.

For instance, given "Alabama", your function could return "AL", "AA", "AB" or "AM" - as long as it doesn't return that value for any of Alaska, Arkansas, etc. ("AA" is only possible because "A" appears more than once in the state name.)

Standard loopholes forbidden. Standard input/output are ok. This is code golf, so shortest solution, in bytes, wins.

The complete list of possible inputs is here:

Alabama
Arizona
Arkansas
California
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming

• Should the output always be two uppercase letters, or is it OK to output mixed case? If mixed is OK should "Ab" be considered as different from "AB"; and must the first letter always be uppercase? Jun 4, 2017 at 2:54
• Is the space character considered a valid letter? Jun 4, 2017 at 3:21
• No. Letters are letters. Jun 4, 2017 at 22:36
• Output must be uppercase. Sorry, I really should have specified that. Jun 4, 2017 at 22:37
• Thanks, I went with both of those rulings as I did think they made the most sense. Jun 4, 2017 at 22:41

# Jelly,  13  12 bytes

907ị;⁸Qḣ2ṢŒu


Try it online! or see a test suite

### How?

907ị;⁸Qḣ2ṢŒu - Monadic link: list of characters, state    e.g. Alabama   or   Kansas
907          - literal 907
ị         - index into state                                b              K
⁸       - link's left argument, state
;        - concatenate                                     bAlabama       KKansas
Q      - de-duplicate (unique by 1st appearance)         bAlam          Kans
ḣ2    - head to index 2                                 bA             Ka
Ṣ   - sort                                            Ab             Ka
Œu - convert to uppercase                            AB             KA


Indexing in Jelly is 1-indexed and modular, so the 907th index of something of length L is the (907-modulo-L)th item. For example for "Alabama" the length is 7 so the item at index 907 is the (907-modulo-7)th, and 907-modulo-7 is 4 (907 = 129 * 7 + 4), so the item at index 907 is 'b'.

907 is the first positive index at which the state abbreviations using index 1 and that index over all of the 50 states become unique.

State names, including their spaces, are of length 4 through 14 inclusive, and 907-modulo-6 is 1 (whereas for all other lengths the value is not 1). This means that if we were to use the 1st and 907th characters for the abbreviations that Alaska, Hawaii, Kansas, Nevada, and Oregon would be AA, HH, KK, NN, and OO respectively - this is not acceptable for Hawaii, Kansas, or Nevada; so an adjustment needs to be made; this is the reason for the concatenation, de-duplication, head to index 2 and sort, this makes Alaska, Hawaii, Kansas, Nevada, and Oregon become AL, HA, KA, NA and OR respectively and does not collide with existing state abbreviations.

• @LevelRiverSt should be OK now, although there is probably a shorter solution than this patch to my original flawed one. Jun 4, 2017 at 4:51
• Can you please add a brief explanation? Jun 4, 2017 at 5:09
• @user1502040 I was doing so, should be clear now, let me know if you don't understand anything. Jun 4, 2017 at 5:33
• How did you come up with this? Jun 4, 2017 at 5:40
• @user1502040 I knew we needed to create the codes from the letters in the input, and that Jelly indexing was modular, so I just looked for an index that gave 50 unique codes (I just wrote some Python code to find such indexes - also finding -341 and -773 within the -1000 to 1000 range). I originally missed the requirement for "other" so patched up the problem (as described). (I have not found anything shorter yet either, although I would not be surprised if there were). Jun 4, 2017 at 5:44

# Ruby, 34 bytes

->s{s[0]+(s[1,8]*999)[445].upcase}


I started off with s[0]+s*99999[x].upcase and found many values of x up to x=100000 which returned unique codes for all 50 states. Unfortunately they all had cases where the second letter of the abbreviation was the first letter of the state duplicated, which is not allowed (unless the letter appears twice in the state name.) So I decided to use the expression s[0]+s[1,8]*999[x] and found the smallest value of x that worked was 445.

Commented in test program, and output

f=->s{s[0]+            #Return character 0 of the input. Then..
(s[1,8]*999)[          #Concatenate 999 copies of the 8 characters starting at character 1 (or till end of name if state has less than 9 characters)
445].upcase         #Return character 445 of the result, converted to uppercase.
}
"Alabama
Arizona
Arkansas
California
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming".split(\$/).map{|i|p [f[i],i]}

["AA", "Alabama"]
["AI", "Arizona"]
["AS", "Arkansas"]
["CR", "California"]
["CT", "Connecticut"]
["DA", "Delaware"]
["FO", "Florida"]
["GO", "Georgia"]
["HA", "Hawaii"]
["IA", "Idaho"]
["IO", "Illinois"]
["ID", "Indiana"]
["IW", "Iowa"]
["KA", "Kansas"]
["KC", "Kentucky"]
["LA", "Louisiana"]
["MI", "Maine"]
["MA", "Maryland"]
["MH", "Massachusetts"]
["MG", "Michigan"]
["MO", "Minnesota"]
["MS", "Mississippi"]
["MU", "Missouri"]
["MN", "Montana"]
["NM", "New Hampshire"]
["NR", "New Jersey"]
["NX", "New Mexico"]
["NO", "New York"]
["NC", "North Carolina"]
["ND", "North Dakota"]
["OI", "Ohio"]
["OO", "Oklahoma"]
["OR", "Oregon"]
["PL", "Pennsylvania"]
["RI", "Rhode Island"]
["SC", "South Carolina"]
["SD", "South Dakota"]
["TS", "Tennessee"]
["TX", "Texas"]
["UA", "Utah"]
["VR", "Vermont"]
["VN", "Virginia"]
["WG", "Washington"]
["WI", "West Virginia"]
["WS", "Wisconsin"]
["WO", "Wyoming"]

• Where did you see the rule that the second letter could not be the same as the first? The example even had "AA" for Alabama. Jun 4, 2017 at 12:45
• The second letter must be one of the other letters of the state. AA for Alabama is fine because Alabama has two A's. KK is fine for Kentucky but not for Kansas for example. Jun 4, 2017 at 13:18

# Python 2, 39 bytes

lambda s:s[0]+s[906%len(s)or 1].upper()


Try it online!

## Python 2, 39 bytes

lambda s:s[0]+s[306%len(s)or-3].upper()


Try it online!

## JavaScript (ES6), 46 bytes

s=>s[0]+s[(s>'M')+1153%s.length].toUpperCase()


### Demo

let f =

s=>s[0]+s[(s>'M')+1153%s.length].toUpperCase()

;[
'Hawaii',       'Idaho',    'Illinois',      'Indiana',     'Iowa',      'Kansas',  'Kentucky',   'Louisiana',    'Maine',        'Maryland',
'New Mexico',   'New York', 'North Carolina','North Dakota','Ohio',      'Oklahoma','Oregon',     'Pennsylvania', 'Rhode Island', 'South Carolina',
'South Dakota', 'Tennessee','Texas',         'Utah',        'Vermont',   'Virginia','Washington', 'West Virginia','Wisconsin',    'Wyoming'
]
.map(
s => console.log(f(s), s)
)

# Retina, 49 46 bytes

\B.*(?=[A-Zflmpxz])|\B.*(?=[hru])

TlL
!^..


Try it online! If the state contains a second uppercase letter, or one of the letters flmpxz, then that becomes the second letter of the code. Otherwise, if it contains one of the letters hru, then that becomes the second letter of the code, otherwise just use the first two letters of the state.

# JavaScript (ES6), 52 bytes

s=>s[0]+(s=s.slice(2,9))[146%s.length].toUpperCase()


f=
s=>s[0]+(s=s.slice(2,9))[146%s.length].toUpperCase()

states = Alabama
Arizona
Arkansas
California
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming.split('\n')

states.forEach(state => console.log(f(state), state))

# JavaScript (ES6), 52 bytes

s=>s[0]+(s[8]||s[s[1]=='o'?5:4]||s[2]).toUpperCase()


f=
s=>s[0]+(s[8]||s[s[1]=='o'?5:4]||s[2]).toUpperCase()

states = Alabama
Arizona
Arkansas
California
Connecticut
Delaware
Florida
Georgia
Hawaii
Idaho
Illinois
Indiana
Iowa
Kansas
Kentucky
Louisiana
Maine
Maryland
Massachusetts
Michigan
Minnesota
Mississippi
Missouri
Montana
New Hampshire
New Jersey
New Mexico
New York
North Carolina
North Dakota
Ohio
Oklahoma
Oregon
Pennsylvania
Rhode Island
South Carolina
South Dakota
Tennessee
Texas
Utah
Vermont
Virginia
Washington
West Virginia
Wisconsin
Wyoming.split('\n')

states.forEach(state => console.log(f(state), state))`

• Hawaii, Kansas, and Nevada have now got invalid abbreviations. (The second letter must be one of the other letters of the state.) I resolved this exact issue in my Jelly solution. Jun 4, 2017 at 6:50
• Ah, how tricky! I'll have to revert to my first answer, good thing I saved it. Jun 4, 2017 at 7:05