State name puzzle

From Rosetta Code
Task
State name puzzle
You are encouraged to solve this task according to the task description, using any language you may know.

Background

This task is inspired by Mark Nelson's DDJ Column "Wordplay" and one of the weekly puzzle challenges from Will Shortz on NPR Weekend Edition [1] and originally attributed to David Edelheit.

The challenge was to take the names of two U.S. States, mix them all together, then rearrange the letters to form the names of two different U.S. States (so that all four state names differ from one another).

What states are these?


The problem was reissued on the Unicon Discussion Web which includes several solutions with analysis. Several techniques may be helpful and you may wish to refer to Gödel numbering, equivalence relations, and equivalence classes. The basic merits of these were discussed in the Unicon Discussion Web.

A second challenge in the form of a set of fictitious new states was also presented.


Task

Write a program to solve the challenge using both the original list of states and the fictitious list.


Caveats
  • case and spacing aren't significant - just letters (harmonize case)
  • don't expect the names to be in any order - such as being sorted
  • don't rely on names to be unique (eliminate duplicates - meaning if Iowa appears twice you can only use it once)


Comma separated list of state names used in the original puzzle:

    "Alabama",  "Alaska",  "Arizona",  "Arkansas",
    "California",  "Colorado",  "Connecticut",  "Delaware",  
    "Florida",  "Georgia",  "Hawaii",  "Idaho",  "Illinois",  
    "Indiana",  "Iowa",  "Kansas",  "Kentucky",  "Louisiana",
    "Maine",  "Maryland",  "Massachusetts",  "Michigan",
    "Minnesota",  "Mississippi",  "Missouri",  "Montana",
    "Nebraska",  "Nevada",  "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"

Comma separated list of additional fictitious state names to be added to the original (Includes a duplicate):

"New Kory",  "Wen Kory",  "York New",  "Kory New",  "New Kory"


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



11l

Translation of: Python
V states = [‘Alabama’, ‘Alaska’, ‘Arizona’, ‘Arkansas’,
‘California’, ‘Colorado’, ‘Connecticut’, ‘Delaware’, ‘Florida’,
‘Georgia’, ‘Hawaii’, ‘Idaho’, ‘Illinois’, ‘Indiana’, ‘Iowa’, ‘Kansas’,
‘Kentucky’, ‘Louisiana’, ‘Maine’, ‘Maryland’, ‘Massachusetts’,
‘Michigan’, ‘Minnesota’, ‘Mississippi’, ‘Missouri’, ‘Montana’,
‘Nebraska’, ‘Nevada’, ‘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’]

states = sorted(states)

DefaultDict[String, [String]] smap
L(s1) states[0 .< (len)-1]
   V i = L.index
   L(s2) states[i+1..]
      smap[sorted(s1‘’s2)].append(s1‘ + ’s2)

L(pairs) sorted(smap.values())
   I pairs.len > 1
      print(pairs.join(‘ = ’))
Output:
North Carolina + South Dakota = North Dakota + South Carolina

AppleScript

use AppleScript version "2.3.1" -- Mac OS X 10.9 (Mavericks) or later.
use sorter : script ¬
    "Custom Iterative Ternary Merge Sort" -- <www.macscripter.net/t/timsort-and-nigsort/71383/3>

on stateNamePuzzle()
    script o
        property stateNames : {"Alabama", "Alaska", "Arizona", "Arkansas", ¬
            "California", "Colorado", "Connecticut", "Delaware", ¬
            "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", ¬
            "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", ¬
            "Maine", "Maryland", "Massachusetts", "Michigan", ¬
            "Minnesota", "Mississippi", "Missouri", "Montana", ¬
            "Nebraska", "Nevada", "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", ¬
            "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"}
        property workList : {}
        
        -- Custom comparison handler for the sort.
        on isGreater(a, b)
            return (beginning of a > beginning of b)
        end isGreater
    end script
    
    ignoring case
        -- Remove duplicates.
        repeat with i from 1 to (count o's stateNames)
            set thisName to o's stateNames's item i
            if ({thisName} is not in o's workList) then set end of o's workList to thisName
        end repeat
        set o's stateNames to o's workList
        
        -- Build a list of lists containing unique pairs of names preceded by
        -- text composed of their combined and sorted visible characters.
        set o's workList to {}
        set stateCount to (count o's stateNames)
        repeat with i from 1 to (stateCount - 1)
            set name1 to o's stateNames's item i
            repeat with j from (i + 1) to stateCount
                set name2 to o's stateNames's item j
                set chrs to (name1 & name2)'s characters
                tell sorter to sort(chrs, 1, -1, {})
                set end of o's workList to {join(chrs, "")'s word 1, {name1, name2}}
            end repeat
        end repeat
        
        -- Sort the lists on the character strings
        set pairCount to (count o's workList)
        tell sorter to sort(o's workList, 1, pairCount, {comparer:o})
        
        -- Look for groups of equal character strings and match
        -- associated name pairs not containing the same name(s).
        set output to {}
        set l to 1
        repeat while (l < pairCount)
            set chrs to beginning of o's workList's item l
            set r to l
            repeat while ((r < pairCount) and (beginning of o's workList's item (r + 1) = chrs))
                set r to r + 1
            end repeat
            if (r > l) then
                repeat with i from l to (r - 1)
                    set {name1, name2} to end of o's workList's item i
                    set text1 to join(result, " and ") & " --> "
                    repeat with j from (i + 1) to r
                        set pair2 to end of o's workList's item j
                        if (not (({name1} is in pair2) or ({name2} is in pair2))) then
                            set end of output to text1 & join(pair2, " and ")
                        end if
                    end repeat
                end repeat
            end if
            set l to r + 1
        end repeat
    end ignoring
    
    return join(output, linefeed)
end stateNamePuzzle

on join(lst, delim)
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to delim
    set txt to lst as text
    set AppleScript's text item delimiters to astid
    return txt
end join

stateNamePuzzle()
Output:
"North Carolina and South Dakota --> North Dakota and South Carolina
New York and New Kory --> Wen Kory and York New
New York and New Kory --> Wen Kory and Kory New
New York and New Kory --> York New and Kory New
New York and Wen Kory --> New Kory and York New
New York and Wen Kory --> New Kory and Kory New
New York and Wen Kory --> York New and Kory New
New York and York New --> New Kory and Wen Kory
New York and York New --> New Kory and Kory New
New York and York New --> Wen Kory and Kory New
New York and Kory New --> New Kory and Wen Kory
New York and Kory New --> New Kory and York New
New York and Kory New --> Wen Kory and York New
New Kory and Wen Kory --> York New and Kory New
New Kory and York New --> Wen Kory and Kory New
New Kory and Kory New --> Wen Kory and York New"

Bracmat

(     Alabama
      Alaska
      Arizona
      Arkansas
      California
      Colorado
      Connecticut
      Delaware
      Florida
      Georgia
      Hawaii
      Idaho
      Illinois
      Indiana
      Iowa
      Kansas
      Kentucky
      Louisiana
      Maine
      Maryland
      Massachusetts
      Michigan
      Minnesota
      Mississippi
      Missouri
      Montana
      Nebraska
      Nevada
      "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
  : ?states
& "New Kory" "Wen Kory" "York New" "Kory New" "New Kory":?extrastates
& ( "State name puzzle"
  =     allStates State state statechars char
      , A Z S1 S2 S3 S4 L1 L2 L3 L4 L12
    .   0:?allStates
      &   whl
        ' ( !arg:%?State ?arg
          & low$!State:?state
          & 0:?statechars
          &   whl
            ' ( @(!state:? (%@:~" ":?char) ?state)
              & !char+!statechars:?statechars
              )
          & (!State.!statechars)+!allStates:?allStates
          )
      & (   !allStates
          :   ?
            + ?*(?S1.?L1)
            + ?A
            + ?*(?S2.?L2)
            + ( ?Z
              & !L1+!L2:?L12
              &   !A+!Z
                :   ?
                  + ?*(?S3.?L3&!L12+-1*!L3:?L4)
                  + ?
                  +   ?
                    * ( ?S4
                      .   !L4
                        & out$(!S1 "+" !S2 "=" !S3 "+" !S4)
                        & ~
                      )
                  + ?
              )
        | out$"No more solutions"
        )
  )
& "State name puzzle"$!states
& "State name puzzle"$(!states !extrastates)
);

Output:

North Carolina + South Dakota = North Dakota + South Carolina
No more solutions
Kory New + New Kory = New York + Wen Kory
Kory New + New Kory = New York + York New
Kory New + New Kory = Wen Kory + York New
Kory New + New York = New Kory + Wen Kory
Kory New + New York = New Kory + York New
Kory New + New York = Wen Kory + York New
Kory New + Wen Kory = New Kory + New York
Kory New + Wen Kory = New Kory + York New
Kory New + Wen Kory = New York + York New
Kory New + York New = New Kory + New York
Kory New + York New = New Kory + Wen Kory
Kory New + York New = New York + Wen Kory
New Kory + New York = Wen Kory + York New
New Kory + Wen Kory = New York + York New
New Kory + York New = New York + Wen Kory
North Carolina + South Dakota = North Dakota + South Carolina
No more solutions

C

Sort by letter occurence and deal with dupes.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define USE_FAKES 1

const char *states[] = {
#if USE_FAKES
	"New Kory", "Wen Kory", "York New", "Kory New", "New Kory",
#endif
	"Alabama", "Alaska", "Arizona", "Arkansas",
	"California", "Colorado", "Connecticut",
	"Delaware",    
	"Florida", "Georgia", "Hawaii",
	"Idaho", "Illinois", "Indiana", "Iowa",
	"Kansas", "Kentucky", "Louisiana",
	"Maine", "Maryland", "Massachusetts", "Michigan",
	"Minnesota", "Mississippi", "Missouri", "Montana",
	"Nebraska", "Nevada", "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"
};

int n_states = sizeof(states)/sizeof(*states);
typedef struct { unsigned char c[26]; const char *name[2]; } letters;

void count_letters(letters *l, const char *s)
{
	int c;
	if (!l->name[0]) l->name[0] = s;
	else l->name[1] = s;

	while ((c = *s++)) {
		if (c >= 'a' && c <= 'z') l->c[c - 'a']++;
		if (c >= 'A' && c <= 'Z') l->c[c - 'A']++;
	}
}

int lcmp(const void *aa, const void *bb)
{
	int i;
	const letters *a = aa, *b = bb;
	for (i = 0; i < 26; i++)
		if      (a->c[i] > b->c[i]) return  1;
		else if (a->c[i] < b->c[i]) return -1;
	return 0;
}

int scmp(const void *a, const void *b)
{
	return strcmp(*(const char *const *)a, *(const char *const *)b);
}

void no_dup()
{
	int i, j;

	qsort(states, n_states, sizeof(const char*), scmp);

	for (i = j = 0; i < n_states;) {
		while (++i < n_states && !strcmp(states[i], states[j]));
		if (i < n_states) states[++j] = states[i];
	}

	n_states = j + 1;
}

void find_mix()
{
	int i, j, n;
	letters *l, *p;

	no_dup();
	n = n_states * (n_states - 1) / 2;
	p = l = calloc(n, sizeof(letters));

	for (i = 0; i < n_states; i++)
		for (j = i + 1; j < n_states; j++, p++) {
			count_letters(p, states[i]);
			count_letters(p, states[j]);
		}

	qsort(l, n, sizeof(letters), lcmp);

	for (j = 0; j < n; j++) {
		for (i = j + 1; i < n && !lcmp(l + j, l + i); i++) {
			if (l[j].name[0] == l[i].name[0]
				|| l[j].name[1] == l[i].name[0]
				|| l[j].name[1] == l[i].name[1])
				continue;
			printf("%s + %s => %s + %s\n",
				l[j].name[0], l[j].name[1], l[i].name[0], l[i].name[1]);
		}
	}
	free(l);
}

int main(void)
{
	find_mix();
	return 0;
}

C++

Ported from C solution.

#include <algorithm>
#include <iostream>
#include <string>
#include <array>
#include <vector>

template<typename T>
T unique(T&& src)
{
    T retval(std::move(src));
    std::sort(retval.begin(), retval.end(), std::less<typename T::value_type>());
    retval.erase(std::unique(retval.begin(), retval.end()), retval.end());
    return retval;
}

#define USE_FAKES 1

auto states = unique(std::vector<std::string>({
#if USE_FAKES
    "Slender Dragon", "Abalamara",
#endif
    "Alabama", "Alaska", "Arizona", "Arkansas",
    "California", "Colorado", "Connecticut",
    "Delaware",
    "Florida", "Georgia", "Hawaii",
    "Idaho", "Illinois", "Indiana", "Iowa",
    "Kansas", "Kentucky", "Louisiana",
    "Maine", "Maryland", "Massachusetts", "Michigan",
    "Minnesota", "Mississippi", "Missouri", "Montana",
    "Nebraska", "Nevada", "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"
}));

struct counted_pair
{
    std::string name;
    std::array<int, 26> count{};

    void count_characters(const std::string& s)
    {
        for (auto&& c : s) {
            if (c >= 'a' && c <= 'z') count[c - 'a']++;
            if (c >= 'A' && c <= 'Z') count[c - 'A']++;
        }
    }

    counted_pair(const std::string& s1, const std::string& s2)
        : name(s1 + " + " + s2)
    {
        count_characters(s1);
        count_characters(s2);
    }
};

bool operator<(const counted_pair& lhs, const counted_pair& rhs)
{
    auto lhs_size = lhs.name.size();
    auto rhs_size = rhs.name.size();
    return lhs_size == rhs_size
            ? std::lexicographical_compare(lhs.count.begin(),
                                           lhs.count.end(),
                                           rhs.count.begin(),
                                           rhs.count.end())
            : lhs_size < rhs_size;
}

bool operator==(const counted_pair& lhs, const counted_pair& rhs)
{
    return lhs.name.size() == rhs.name.size() && lhs.count == rhs.count;
}

int main()
{
    const int n_states = states.size();

    std::vector<counted_pair> pairs;
    for (int i = 0; i < n_states; i++) {
        for (int j = 0; j < i; j++) {
            pairs.emplace_back(counted_pair(states[i], states[j]));
        }
    }
    std::sort(pairs.begin(), pairs.end());

    auto start = pairs.begin();
    while (true) {
        auto match = std::adjacent_find(start, pairs.end());
        if (match == pairs.end()) {
            break;
        }
        auto next = match + 1;
        std::cout << match->name << " => " << next->name << "\n";
        start = next;
    }
}

Clojure

(ns clojure-sandbox.statenames
  (:require [clojure.data.csv :as csv]
            [clojure.java.io :as io]
            [clojure.string :refer [lower-case]]
            [clojure.math.combinatorics :as c]
            [clojure.pprint :as pprint]))

(def made-up-states ["New Kory" "Wen Kory" "York New" "Kory New" "New Kory"])

;; I saved the list of states in a local file to keep the code clean but you can copy and paste the list instead
(def real-states (with-open [in-file (io/reader (io/resource "states.csv"))]
                   (->> (doall
                         (csv/read-csv in-file))
                        (map first))))

(defn- state->charset [state-name]
  "Convert state name into sorted list of characters with no spaces"
  (->> state-name
       char-array
       sort
       (filter (set (map char (range 97 123)))))) ;; ASCII range for lower case letters

(defn- add-charsets [states]
  "Calculate sorted character list for each state and store with name"
  (->> states
       (map lower-case) ;; Convert all names to lower case
       set ;; remove duplicates
       (map
        (fn [s] {:name s
                 :characters (state->charset s)})))) ;; add characters

(defn- pair-chars [state1 state2]
  "Join the characters of two states together and sort them"
  (-> state1
      :characters
      (concat (:characters state2))
      sort))

(defn- pair [[state1 state2]]
  "Record representing two state names and the total characters used in them"
  {:inputs [(:name state1) (:name state2)]
   :characters (pair-chars state1 state2)})

(defn- find-all-pairs [elements]
  (c/combinations elements 2))

(defn- pairs-to-search [state-names]
  "Create character lists for all states and return a list of all possible pairs"
  (->> state-names
       add-charsets
       find-all-pairs
       (map pair)))

(defn- pairs-have-same-letters? [[pair1 pair2]]
  (= (:characters pair1) (:characters pair2)))

(defn- inputs-are-distinct? [[pair1 pair2 :as pairs]]
  "Check that two pairs of states don't contain the same state"
  (= 4 ;; There should be a total of 4 distinct states in the two pairs
     (->> pairs
          (map :inputs)
          flatten
          set
          count)))

(defn- search [pairs]
  (->> pairs
       find-all-pairs ;; find pairs of pairs to search
       (filter pairs-have-same-letters?) ;; Keep only those where each pair has the same characters
       (filter inputs-are-distinct?))) ;; Remove pairs with duplicate states

(defn find-matches [state-names]
  "Find all state pairs and return pairs of them using the same letters"
  (-> state-names
      pairs-to-search
      search))

(defn- format-match-output [[pair1 pair2]]
  "Format a pair of state pairs to print out"
  (str (first (:inputs pair1))
       " + "
       (last (:inputs pair1))
       " = "
       (first (:inputs pair2))
       " + "
       (last (:inputs pair2))))

(defn- evaluate-and-print [states]
  (->> states
       find-matches
       (map format-match-output)
       pprint/pprint))

(defn -main [& args]
  (println "Solutions for 50 real states")
  (evaluate-and-print real-states)
  (println "Solutions with made up states added")
  (evaluate-and-print (concat real-states made-up-states)))
Output:
Solutions for 50 real states
("north carolina + south dakota = south carolina + north dakota")
Solutions with made up states added
("new york + new kory = kory new + york new"
 "new york + new kory = kory new + wen kory"
 "new york + new kory = york new + wen kory"
 "new york + kory new = new kory + york new"
 "new york + kory new = new kory + wen kory"
 "new york + kory new = york new + wen kory"
 "new york + york new = new kory + kory new"
 "new york + york new = new kory + wen kory"
 "new york + york new = kory new + wen kory"
 "new york + wen kory = new kory + kory new"
 "new york + wen kory = new kory + york new"
 "new york + wen kory = kory new + york new"
 "north carolina + south dakota = south carolina + north dakota"
 "new kory + kory new = york new + wen kory"
 "new kory + york new = kory new + wen kory"
 "new kory + wen kory = kory new + york new")

D

import std.stdio, std.algorithm, std.string, std.exception;

auto states = ["Alabama", "Alaska", "Arizona", "Arkansas",
"California", "Colorado", "Connecticut", "Delaware", "Florida",
"Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
"Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
"Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
"Nebraska", "Nevada", "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",
// Uncomment the next line for the fake states.
// "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"
];

void main() {
  states.length -= states.sort().uniq.copy(states).length;

  string[][const ubyte[]] smap;
  foreach (immutable i, s1; states[0 .. $ - 1])
    foreach (s2; states[i + 1 .. $])
      smap[(s1 ~ s2).dup.representation.sort().release.assumeUnique]
        ~= s1 ~ " + " ~ s2;

  writefln("%-(%-(%s = %)\n%)",
           smap.values.sort().filter!q{ a.length > 1 });
}
Output:
North Carolina + South Dakota = North Dakota + South Carolina

F#

// State name puzzle. Nigel Galloway: February 9th., 2023
let states=["Alabama"; "Alaska"; "Arizona"; "Arkansas"; "California"; "Colorado"; "Connecticut"; "Delaware"; "Florida"; "Georgia"; "Hawaii"; "Idaho"; "Illinois"; "Indiana"; "Iowa"; "Kansas"; "Kentucky"; "Louisiana"; "Maine"; "Maryland"; "Massachusetts"; "Michigan"; "Minnesota"; "Mississippi"; "Missouri"; "Montana"; "Nebraska"; "Nevada"; "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"; "New Kory"; "Wen Kory"; "York New"; "Kory New"; "New Kory"]|>List.distinct
let fN(i,g)(e,l)=let n=Array.zeroCreate<int>256
                 let fN i g=n[g]<-n[g]+i
                 let fG n g=(g:string).ToLower().ToCharArray()|>Array.iter(fun g->fN n (int g))
                 fG 1 i; fG 1 g; fG -1 e; fG -1 l; n|>Array.forall((=)0) 
let n=states|>List.allPairs states|>List.filter(fun(n,g)->n<g)|>List.groupBy(fun(n,g)->n.Length+g.Length)
let g=n|>List.map(fun(_,n)->n|>List.allPairs n|>List.filter(fun((n,g),(n',g'))->(n,g)<(n',g') && n<>n' && n<>g' && g<>n' && g<>g' && fN(n,g)(n',g')))|>List.filter(List.isEmpty>>not)
g|>List.iter(List.iter(fun((i,g),(e,l))->printfn $"%s{i},%s{g}->%s{e},%s{l}"))
Output:
New Kory,New York->Wen Kory,York New
New Kory,Wen Kory->New York,York New
New Kory,York New->New York,Wen Kory
Kory New,New York->New Kory,Wen Kory
Kory New,New York->New Kory,York New
Kory New,New York->Wen Kory,York New
Kory New,New Kory->New York,Wen Kory
Kory New,New Kory->New York,York New
Kory New,New Kory->Wen Kory,York New
Kory New,Wen Kory->New York,York New
Kory New,Wen Kory->New Kory,New York
Kory New,Wen Kory->New Kory,York New
Kory New,York New->New York,Wen Kory
Kory New,York New->New Kory,New York
Kory New,York New->New Kory,Wen Kory
North Carolina,South Dakota->North Dakota,South Carolina

Go

package main

import (
    "fmt"
    "unicode"
)

var states = []string{"Alabama", "Alaska", "Arizona", "Arkansas",
    "California", "Colorado", "Connecticut",
    "Delaware",
    "Florida", "Georgia", "Hawaii",
    "Idaho", "Illinois", "Indiana", "Iowa",
    "Kansas", "Kentucky", "Louisiana",
    "Maine", "Maryland", "Massachusetts", "Michigan",
    "Minnesota", "Mississippi", "Missouri", "Montana",
    "Nebraska", "Nevada", "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"}

func main() {
    play(states)
    play(append(states,
        "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"))
}

func play(states []string) {
    fmt.Println(len(states), "states:")
    // get list of unique state names
    set := make(map[string]bool, len(states))
    for _, s := range states {
        set[s] = true
    }
    // make parallel arrays for unique state names and letter histograms
    s := make([]string, len(set))
    h := make([][26]byte, len(set))
    var i int
    for us := range set {
        s[i] = us
        for _, c := range us {
            if u := uint(unicode.ToLower(c)) - 'a'; u < 26 {
                h[i][u]++
            }
        }
        i++
    }
    // use map to find matches.  map key is sum of histograms of
    // two different states.  map value is indexes of the two states.
    type pair struct {
        i1, i2 int
    }
    m := make(map[string][]pair)
    b := make([]byte, 26) // buffer for summing histograms
    for i1, h1 := range h {
        for i2 := i1 + 1; i2 < len(h); i2++ {
            // sum histograms
            for i := range b {
                b[i] = h1[i] + h[i2][i]
            }
            k := string(b) // make key from buffer.
            // now loop over any existing pairs with the same key,
            // printing any where both states of this pair are different
            // than the states of the existing pair
            for _, x := range m[k] {
                if i1 != x.i1 && i1 != x.i2 && i2 != x.i1 && i2 != x.i2 {
                    fmt.Printf("%s, %s = %s, %s\n", s[i1], s[i2],
                        s[x.i1], s[x.i2])
                }
            }
            // store this pair in the map whether printed or not.
            m[k] = append(m[k], pair{i1, i2})
        }
    }
}

Output:

50 states:
North Dakota, South Carolina = North Carolina, South Dakota
55 states:
South Dakota, North Carolina = North Dakota, South Carolina
New Kory, Kory New = Wen Kory, York New
New Kory, Kory New = Wen Kory, New York
New Kory, York New = Wen Kory, Kory New
New Kory, York New = Wen Kory, New York
New Kory, New York = Wen Kory, Kory New
New Kory, New York = Wen Kory, York New
Kory New, York New = Wen Kory, New Kory
Kory New, York New = Wen Kory, New York
Kory New, York New = New Kory, New York
Kory New, New York = Wen Kory, New Kory
Kory New, New York = Wen Kory, York New
Kory New, New York = New Kory, York New
York New, New York = Wen Kory, New Kory
York New, New York = Wen Kory, Kory New
York New, New York = New Kory, Kory New

Haskell

{-# LANGUAGE TupleSections #-}

import Data.Char (isLetter, toLower)
import Data.Function (on)
import Data.List (groupBy, nub, sort, sortBy)

-------------------- STATE NAME PUZZLE -------------------

puzzle :: [String] -> [((String, String), (String, String))]
puzzle states =
  concatMap
    ((filter isValid . pairs) . map snd)
    ( filter ((> 1) . length) $
        groupBy ((==) `on` fst) $
          sortBy
            (compare `on` fst)
            [ (pkey (a <> b), (a, b))
              | (a, b) <- pairs (nub $ sort states)
            ]
    )
  where
    pkey = sort . filter isLetter . map toLower
    isValid ((a0, a1), (b0, b1)) =
      (a0 /= b0)
        && (a0 /= b1)
        && (a1 /= b0)
        && (a1 /= b1)

pairs :: [a] -> [(a, a)]
pairs [] = []
pairs (y : ys) = map (y,) ys <> pairs ys

--------------------------- TEST -------------------------
main :: IO ()
main = do
  putStrLn $
    "Matching pairs generated from "
      <> show (length stateNames)
      <> " state names and "
      <> show (length fakeStateNames)
      <> " fake state names:"
  mapM_ print $ puzzle $ stateNames <> fakeStateNames

stateNames :: [String]
stateNames =
  [ "Alabama",
    "Alaska",
    "Arizona",
    "Arkansas",
    "California",
    "Colorado",
    "Connecticut",
    "Delaware",
    "Florida",
    "Georgia",
    "Hawaii",
    "Idaho",
    "Illinois",
    "Indiana",
    "Iowa",
    "Kansas",
    "Kentucky",
    "Louisiana",
    "Maine",
    "Maryland",
    "Massachusetts",
    "Michigan",
    "Minnesota",
    "Mississippi",
    "Missouri",
    "Montana",
    "Nebraska",
    "Nevada",
    "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"
  ]

fakeStateNames :: [String]
fakeStateNames =
  [ "New Kory",
    "Wen Kory",
    "York New",
    "Kory New",
    "New Kory"
  ]
Output:
Matching pairs generated from 50 state names and 5 fake state names:
(("North Carolina","South Dakota"),("North Dakota","South Carolina"))
(("Kory New","New Kory"),("New York","Wen Kory"))
(("Kory New","New Kory"),("New York","York New"))
(("Kory New","New Kory"),("Wen Kory","York New"))
(("Kory New","New York"),("New Kory","Wen Kory"))
(("Kory New","New York"),("New Kory","York New"))
(("Kory New","New York"),("Wen Kory","York New"))
(("Kory New","Wen Kory"),("New Kory","New York"))
(("Kory New","Wen Kory"),("New Kory","York New"))
(("Kory New","Wen Kory"),("New York","York New"))
(("Kory New","York New"),("New Kory","New York"))
(("Kory New","York New"),("New Kory","Wen Kory"))
(("Kory New","York New"),("New York","Wen Kory"))
(("New Kory","New York"),("Wen Kory","York New"))
(("New Kory","Wen Kory"),("New York","York New"))
(("New Kory","York New"),("New York","Wen Kory"))

Icon and Unicon

Equivalence Class Solution

link strings                 # for csort and deletec

procedure main(arglist)
    ECsolve(S1 := getStates())     # original state names puzzle
    ECsolve(S2 := getStates2())    # modified fictious names puzzle 
    GNsolve(S1)
    GNsolve(S2)
end

procedure ECsolve(S)         # Solve challenge using equivalence classes
    local T,x,y,z,i,t,s,l,m
    st := &time              # mark runtime
    /S := getStates()        # default
    every insert(states := set(),deletec(map(!S),' \t'))  # ignore case & space
    
    # Build a table containing sets of state name pairs 
    # keyed off of canonical form of the pair
    # Use csort(s) rather than cset(s) to preserve the numbers of each letter
    # Since we care not of X&Y .vs. Y&X keep only X&Y
    
    T := table()
    every (x := !states ) & ( y := !states ) do
    if z := csort(x || (x << y)) then {
        /T[z] := []
        put(T[z],set(x,y))
    }
    
    # For each unique key (canonical pair) find intersection of all pairs
    # Output is <current key matched> <key> <pairs>
    
    i := m := 0       # keys (i) and pairs (m) matched
    every z := key(T) do {
        s := &null
        every l := !T[z] do {
            /s :=  l
            s **:= l
        }
        if *s = 0 then {
            i +:= 1
            m +:= *T[z]
            every x := !T[z] do {
                #writes(i," ",z)  # uncomment for equiv class and match count
                every writes(!x," ")
                write()
            }
        }
    }
    write("... runtime ",(&time - st)/1000.,"\n",m," matches found.")
end

The following are common routines:

procedure getStates()   # return list of state names
return ["Alabama", "Alaska", "Arizona", "Arkansas",
       "California", "Colorado", "Connecticut",
       "Delaware",    
       "Florida", "Georgia", "Hawaii",
       "Idaho", "Illinois", "Indiana", "Iowa",
       "Kansas", "Kentucky", "Louisiana",
       "Maine", "Maryland", "Massachusetts", "Michigan",
       "Minnesota", "Mississippi", "Missouri", "Montana",
       "Nebraska", "Nevada", "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"]
end

procedure getStates2() # return list of state names + fictious states
return getStates() ||| ["New Kory", "Wen Kory", "York New", "Kory New", "New Kory"]
end

Godel Number Solution

link factors

procedure GNsolve(S)
    local min, max
    st := &time
    equivClasses := table()
    statePairs := table()
    /S := getStates()
    every put(states := [], map(!S)) # Make case insignificant
    min := proc("min",0)             # Link "factors" loses max/min functions
    max := proc("max",0)             # ... these statements get them back
    
    # Build a table of equivalence classes (all state pairs in the
    #   same equivalence class have the same characters in them)
    #   Output new pair couples *before* adding each state pair to class.
    
    every (state1 := |get(states)) & (state2 := !states) do {
        if state1 ~== state2 then {
            statePair := min(state1, state2)||":"||max(state1,state2)
            if /statePairs[statePair] := set(state1, state2) then {
                signature := getClassSignature(state1, state2)
                /equivClasses[signature] := set()
                every *(statePairs[statePair] **   # require 4 distinct states
                statePairs[pair := !equivClasses[signature]]) == 0 do {
                    write(statePair, " and ", pair)
                }
                insert(equivClasses[signature], statePair)
            }
        }
    }
    
    write(&errout, "Time: ", (&time-st)/1000.0)
end

# Build a (Godel) signature identifying the equivalence class for state pair s.

procedure getClassSignature(s1, s2)
    static G
    initial G := table()
    /G[s1] := gn(s1)
    /G[s2] := gn(s2)
    return G[s1]*G[s2]
end

procedure gn(s)  # Compute the Godel number for a string (letters only)
    static xlate
    local p, i, z
    initial {
        xlate := table(1)
        p := create prime()
        every i := 1 to 26 do {
            xlate[&lcase[i]] := xlate[&ucase[i]] := @p
        }
    }
    z := 1
    every z *:= xlate[!s]
    return z
end

strings.icn provides deletec, csort factors.icn provides prime

Sample Output (ECsolve):

northcarolina southdakota
northdakota southcarolina
... runtime 0.019
2 matches found.
wenkory yorknew
wenkory newyork
newyork yorknew
wenkory korynew
newyork korynew
newkory korynew
korynew yorknew
wenkory newkory
newkory newyork
newkory yorknew
northcarolina southdakota
northdakota southcarolina
... runtime 0.026
12 matches found.

Sample Output (GNsolve):

north dakota:south carolina and north carolina:south dakota
Time: 0.008999999999999999
north dakota:south carolina and north carolina:south dakota
new kory:wen kory and new york:york new
new kory:wen kory and kory new:new york
new kory:york new and new york:wen kory
new kory:york new and kory new:new york
kory new:new kory and new york:wen kory
kory new:new kory and new york:york new
wen kory:york new and kory new:new york
wen kory:york new and kory new:new kory
wen kory:york new and new kory:new york
kory new:wen kory and new york:york new
kory new:wen kory and new kory:york new
kory new:wen kory and new kory:new york
kory new:york new and new york:wen kory
kory new:york new and new kory:wen kory
kory new:york new and new kory:new york
Time: 0.018

J

Implementation:

require'strings stats'

states=:<;._2]0 :0-.LF

Alabama,Alaska,Arizona,Arkansas,California,Colorado,
Connecticut,Delaware,Florida,Georgia,Hawaii,Idaho,
Illinois,Indiana,Iowa,Kansas,Kentucky,Louisiana,
Maine,Maryland,Massachusetts,Michigan,Minnesota,
Mississippi,Missouri,Montana,Nebraska,Nevada,
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,
Maine,Maine,Maine,Maine,Maine,Maine,Maine,Maine,

)

pairUp=: (#~ matchUp)@({~ 2 comb #)@~.
matchUp=: (i.~ ~: i:~)@:(<@normalize@;"1)
normalize=: /:~@tolower@-.&' '

In action:

   pairUp states
┌──────────────┬──────────────┐
North CarolinaSouth Dakota  
├──────────────┼──────────────┤
North Dakota  South Carolina
└──────────────┴──────────────┘

Note: this approach is sufficient to solve the original problem, but does not properly deal with the addition of fictitious states. So:

isolatePairs=: ~.@matchUp2@(#~ *./@matchUp"2)@({~ 2 comb #)
matchUp2=: /:~"2@:(/:~"1)@(#~ 4=#@~.@,"2)

In action:

   isolatePairs pairUp 'New Kory';'Wen Kory';'York New';'Kory New';'New Kory';states
┌──────────────┬──────────────┐
Kory New      York New      
├──────────────┼──────────────┤
New Kory      Wen Kory      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
New Kory      Wen Kory      
├──────────────┼──────────────┤
New York      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      New York      
├──────────────┼──────────────┤
New Kory      Wen Kory      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      Wen Kory      
├──────────────┼──────────────┤
New Kory      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
New Kory      York New      
├──────────────┼──────────────┤
New York      Wen Kory      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      New York      
├──────────────┼──────────────┤
New Kory      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      New Kory      
├──────────────┼──────────────┤
Wen Kory      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      New Kory      
├──────────────┼──────────────┤
New York      Wen Kory      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      New Kory      
├──────────────┼──────────────┤
New York      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
New Kory      New York      
├──────────────┼──────────────┤
Wen Kory      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      Wen Kory      
├──────────────┼──────────────┤
New Kory      New York      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      York New      
├──────────────┼──────────────┤
New Kory      New York      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      New York      
├──────────────┼──────────────┤
Wen Kory      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      Wen Kory      
├──────────────┼──────────────┤
New York      York New      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
Kory New      York New      
├──────────────┼──────────────┤
New York      Wen Kory      
└──────────────┴──────────────┘

┌──────────────┬──────────────┐
North CarolinaSouth Dakota  
├──────────────┼──────────────┤
North Dakota  South Carolina
└──────────────┴──────────────┘

Java

Works with: Java version 8
import java.util.*;
import java.util.stream.*;

public class StateNamePuzzle {

    static String[] states = {"Alabama", "Alaska", "Arizona", "Arkansas",
        "California", "Colorado", "Connecticut", "Delaware", "Florida",
        "Georgia", "hawaii", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
        "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
        "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
        "Nebraska", "Nevada", "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",
        "New Kory", "Wen Kory", "York New", "Kory New", "New Kory",};

    public static void main(String[] args) {
        solve(Arrays.asList(states));
    }

    static void solve(List<String> input) {
        Map<String, String> orig = input.stream().collect(Collectors.toMap(
                s -> s.replaceAll("\\s", "").toLowerCase(), s -> s, (s, a) -> s));

        input = new ArrayList<>(orig.keySet());

        Map<String, List<String[]>> map = new HashMap<>();
        for (int i = 0; i < input.size() - 1; i++) {
            String pair0 = input.get(i);
            for (int j = i + 1; j < input.size(); j++) {

                String[] pair = {pair0, input.get(j)};
                String s = pair0 + pair[1];
                String key = Arrays.toString(s.chars().sorted().toArray());

                List<String[]> val = map.getOrDefault(key, new ArrayList<>());
                val.add(pair);
                map.put(key, val);
            }
        }

        map.forEach((key, list) -> {
            for (int i = 0; i < list.size() - 1; i++) {
                String[] a = list.get(i);
                for (int j = i + 1; j < list.size(); j++) {
                    String[] b = list.get(j);

                    if (Stream.of(a[0], a[1], b[0], b[1]).distinct().count() < 4)
                        continue;

                    System.out.printf("%s + %s = %s + %s %n", orig.get(a[0]),
                            orig.get(a[1]), orig.get(b[0]), orig.get(b[1]));
                }
            }
        });
    }
}

Output:

Wen Kory + Kory New = York New + New Kory 
Wen Kory + Kory New = York New + New York 
Wen Kory + Kory New = New Kory + New York 
Wen Kory + York New = Kory New + New Kory 
Wen Kory + York New = Kory New + New York 
Wen Kory + York New = New Kory + New York 
Wen Kory + New Kory = Kory New + York New 
Wen Kory + New Kory = Kory New + New York 
Wen Kory + New Kory = York New + New York 
Wen Kory + New York = Kory New + York New 
Wen Kory + New York = Kory New + New Kory 
Wen Kory + New York = York New + New Kory 
Kory New + York New = New Kory + New York 
Kory New + New Kory = York New + New York 
Kory New + New York = York New + New Kory 
South Dakota + North Carolina  = North Dakota + South Carolina 

jq

Works with: jq version 1.4
# Input: a string
# Output: an array, being the exploded form of the normalized input
def normalize:
  explode
  | map(if . >= 97 then (. - 97) elif . >= 65 then (. - 65) else empty end);

# Input: an array of strings
# Output: a dictionary with key:value pairs: normalizedString:string
def dictionary:
  reduce .[] as $s ( {}; . + { ($s|normalize|implode): $s });

# Input: an array of strings (e.g. state names)
# Output: a stream of solutions
def solve:

  # Given a pair of normalized state names as lists of integers:
  def nletters: map(length) | add;

  # input [[s1,s2], [t2,t2]]
  def solved:
    ( .[0] | add | sort) ==  (.[1] | add | sort);

  unique
  | length as $l
  | dictionary as $dictionary
  | ($dictionary | keys | map(explode)) as $states
  | reduce ( range(0; $l) as $s1
                 | range($s1+1; $l) as $s2
                 | range($s1+1; $l) as $t1
	         | select($s2 != $t1)
	         | range($t1+1; $l) as $t2
     	         | select($s2 != $t2)
	         | [[$states[$s1], $states[$s2]], [$states[$t1], $states[$t2]]] ) as $quad
       ([];
        if ($quad[0] | nletters) == ($quad[1] | nletters)
	   and ($quad | solved)
	then . + [$quad | map( map(  $dictionary[ implode ] ))]
	else .
	end)
  | .[];

The task:

def States: [
    "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado",
    "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
    "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine",
    "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi",
    "Missouri", "Montana", "Nebraska", "Nevada", "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"
];

def task:
  "Real state names:",
  (States | solve),
  "",
  "States together with fictional state names:",
  (States + ["New Kory", "Wen Kory", "York New", "Kory New", "New Kory"] | solve)   ;

task
Output:
$ jq -c -n -r -f State_name_puzzle.jq
Real state names:
[["North Carolina","South Dakota"],["North Dakota","South Carolina"]]

States together with fictional state names:
[["Kory New","New Kory"],["New York","Wen Kory"]]
[["Kory New","New Kory"],["New York","York New"]]
[["Kory New","New Kory"],["Wen Kory","York New"]]
[["Kory New","New York"],["New Kory","Wen Kory"]]
[["Kory New","New York"],["New Kory","York New"]]
[["Kory New","New York"],["Wen Kory","York New"]]
[["Kory New","Wen Kory"],["New Kory","New York"]]
[["Kory New","Wen Kory"],["New Kory","York New"]]
[["Kory New","Wen Kory"],["New York","York New"]]
[["Kory New","York New"],["New Kory","New York"]]
[["Kory New","York New"],["New Kory","Wen Kory"]]
[["Kory New","York New"],["New York","Wen Kory"]]
[["New Kory","New York"],["Wen Kory","York New"]]
[["New Kory","Wen Kory"],["New York","York New"]]
[["New Kory","York New"],["New York","Wen Kory"]]
[["North Carolina","South Dakota"],["North Dakota","South Carolina"]]

Julia

Works with: Julia version 0.6
Translation of: Kotlin

Module:

module StateNamePuzzle

const realnames = ["Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
"Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine",
"Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri",
"Montana", "Nebraska", "Nevada", "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"]

const fictitious = ["New Kory", "Wen Kory", "York New", "Kory New", "New Kory"]

function combine(a::AbstractString, b::AbstractString)
    chars = vcat(collect(Char, a), collect(Char, b))
    sort!(chars)
    return join(chars)
end

function solve(input::Vector{<:AbstractString})
    dict = Dict{String,String}()
    for state in input
        key = replace(state, " ", "") |> lowercase
        if !haskey(dict, key)
            dict[key] = state
        end
    end
    keyset = collect(keys(dict))
    solutions = String[]
    duplicates = String[]
    for i in eachindex(keyset), j in (i+1):endof(keyset)
        len1 = length(keyset[i]) + length(keyset[j])
        combined1 = combine(keyset[i], keyset[j])
        for k in eachindex(keyset), l in k+1:endof(keyset)
            k  (i, j) && continue
            l  (i, j) && continue
            len2 = length(keyset[k]) + length(keyset[l])
            len1 != len2 && continue
            combined2 = combine(keyset[k], keyset[l])
            if combined1 == combined2
                f1 = dict[keyset[i]] * " + " * dict[keyset[j]]
                f2 = dict[keyset[k]] * " + " * dict[keyset[l]]
                f3 = f1 * " = " * f2
                f3  duplicates && continue
                push!(solutions, f3)
                f4 = f2 * " = " * f1
                push!(duplicates, f4)
            end
        end
    end
    return sort!(solutions)
end

end  # module StateNamePuzzle

Main:

println("Real states:")
foreach(println, StateNamePuzzle.solve(StateNamePuzzle.realnames))

println("\nReal + fictitious state:")
foreach(println, StateNamePuzzle.solve(vcat(StateNamePuzzle.realnames,
    StateNamePuzzle.fictitious)))
Output:
Real states:
South Dakota + North Carolina = South Carolina + North Dakota

Real + fictitious state:
Kory New + New Kory = New York + York New
Kory New + New Kory = Wen Kory + New York
Kory New + New Kory = Wen Kory + York New
Kory New + New York = New Kory + Wen Kory
Kory New + New York = New Kory + York New
Kory New + New York = Wen Kory + York New
Kory New + Wen Kory = New Kory + New York
Kory New + Wen Kory = New Kory + York New
Kory New + Wen Kory = New York + York New
Kory New + York New = New Kory + New York
Kory New + York New = New Kory + Wen Kory
Kory New + York New = Wen Kory + New York
New Kory + New York = Wen Kory + York New
New Kory + Wen Kory = New York + York New
New Kory + York New = Wen Kory + New York
South Dakota + North Carolina = South Carolina + North Dakota

Kotlin

// version 1.2.10

fun solve(states: List<String>) {
    val dict = mutableMapOf<String, String>()
    for (state in states) {
        val key = state.toLowerCase().replace(" ", "")
        if (dict[key] == null) dict.put(key, state)
    }
    val keys = dict.keys.toList()
    val solutions = mutableListOf<String>()
    val duplicates = mutableListOf<String>()
    for (i in 0 until keys.size) {
        for (j in i + 1 until keys.size) {
            val len = keys[i].length + keys[j].length
            val chars = (keys[i] + keys[j]).toCharArray()
            chars.sort()
            val combined = String(chars)
            for (k in 0 until keys.size) {
                for (l in k + 1 until keys.size) {
                    if (k == i || k == j || l == i || l == j) continue
                    val len2 = keys[k].length + keys[l].length
                    if (len2 != len) continue
                    val chars2 = (keys[k] + keys[l]).toCharArray()
                    chars2.sort()
                    val combined2 = String(chars2)
                    if (combined == combined2) {
                        val f1 = "${dict[keys[i]]} + ${dict[keys[j]]}"
                        val f2 = "${dict[keys[k]]} + ${dict[keys[l]]}"
                        val f3 = "$f1 = $f2"              
                        if (f3 in duplicates) continue
                        solutions.add(f3)
                        val f4 = "$f2 = $f1"
                        duplicates.add(f4)
                    }
                }
            }
        }
    }
    solutions.sort()
    for ((i, sol) in solutions.withIndex()) {
        println("%2d  %s".format(i + 1, sol))
    }
}

fun main(args: Array<String>) {
    val states = listOf(
        "Alabama", "Alaska", "Arizona", "Arkansas",
        "California", "Colorado", "Connecticut",
        "Delaware",
        "Florida", "Georgia", "Hawaii",
        "Idaho", "Illinois", "Indiana", "Iowa",
        "Kansas", "Kentucky", "Louisiana",
        "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana",
        "Nebraska", "Nevada", "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"
    )
    println("Real states only:")
    solve(states)
    println()
    val fictitious = listOf(
        "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"
    )
    println("Real and fictitious states:")
    solve(states + fictitious)
}
Output:
Real states only:
 1  North Carolina + South Dakota = North Dakota + South Carolina

Real and fictitious states:
 1  New Kory + Kory New = Wen Kory + York New
 2  New Kory + Wen Kory = York New + Kory New
 3  New Kory + York New = Wen Kory + Kory New
 4  New York + Kory New = New Kory + Wen Kory
 5  New York + Kory New = New Kory + York New
 6  New York + Kory New = Wen Kory + York New
 7  New York + New Kory = Wen Kory + Kory New
 8  New York + New Kory = Wen Kory + York New
 9  New York + New Kory = York New + Kory New
10  New York + Wen Kory = New Kory + Kory New
11  New York + Wen Kory = New Kory + York New
12  New York + Wen Kory = York New + Kory New
13  New York + York New = New Kory + Kory New
14  New York + York New = New Kory + Wen Kory
15  New York + York New = Wen Kory + Kory New
16  North Carolina + South Dakota = North Dakota + South Carolina

LiveCode

This is going to be O(N^2).

function pairwiseAnagrams X
   if the optionkey is down then breakpoint
   put the long seconds into T
   put empty into itemsSoFar
   repeat for each item W in X
      put word 1 to -1 of W into W
      if D[W] = 1 then next repeat
      put 1 into D[W]
      repeat for each item W2 in itemsSoFar
         put W,W2 & cr after WPairs[sortChars(W & W2,true)]
      end repeat
      put W & comma after itemsSoFar
   end repeat
   repeat for each key K in WPairs
      put empty into pairsSoFar
      repeat for each line L in WPairs[K]
         repeat for each line L2 in pairsSoFar
            if item 1 of L is among the items of L2 or item 2 of L is among the items of L2 then next repeat
            put L && "and" && L2 & cr after R
         end repeat
         put L & cr after pairsSoFar
      end repeat
   end repeat
   put the long seconds - T
   return char 1 to -2 of R
end pairwiseAnagrams

function sortChars X,lettersOnly
   get charsToItems(X,lettersOnly)
   sort items of it
   return itemsToChars(it)
end sortChars
 
function charsToItems X,lettersOnly
   repeat for each char C in X
      if lettersOnly and C is not in "abcdefghijklmnopqrstuvwxyz" then next repeat
      put C & comma after R
   end repeat
   return char 1 to -2 of R
end charsToItems
 
function itemsToChars X
   replace comma with empty in X
   return X
end itemsToChars

Mathematica /Wolfram Language

letters[words_,n_] := Sort[Flatten[Characters /@ Take[words,n]]];
groupSameQ[g1_, g2_] := Sort /@ Partition[g1, 2] === Sort /@ Partition[g2, 2];
permutations[{a_, b_, c_, d_}] = Union[Permutations[{a, b, c, d}], SameTest -> groupSameQ];
Select[Flatten[permutations /@ 
   Subsets[Union[ToLowerCase/@{"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "Florida", 
      "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", 
      "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "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"}], {4}], 1], 
 letters[#, 2] === letters[#, -2] &]

Nim

import algorithm, sequtils, strformat, strutils, tables


const
  States = @["Alabama",  "Alaska",  "Arizona",  "Arkansas",
             "California",  "Colorado",  "Connecticut",  "Delaware",
             "Florida",  "Georgia",  "Hawaii",  "Idaho",  "Illinois",
             "Indiana",  "Iowa",  "Kansas",  "Kentucky",  "Louisiana",
             "Maine",  "Maryland",  "Massachusetts",  "Michigan",
             "Minnesota",  "Mississippi",  "Missouri",  "Montana",
             "Nebraska",  "Nevada",  "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"]

  Fictitious = @["New Kory", "Wen Kory", "York New", "Kory New", "New Kory"]

type MatchingPairs = ((string, string), (string, string))


proc matchingPairs(states: openArray[string]): seq[MatchingPairs] =
  ## Build the list of matching pairs of states.

  let states = sorted(states).deduplicate()

  # Build a mapping from ordered sequence of chars to sequence of (state, state).
  var mapping: Table[seq[char], seq[(string, string)]]
  for i in 0..<states.high:
    let s1 = states[i]
    for j in (i + 1)..states.high:
      let s2 = states[j]
      mapping.mgetOrPut(sorted(map(s1 & s2, toLowerAscii)), @[]).add (s1, s2)

  # Keep only the couples of pairs of states with no common state.
  for pairs in mapping.values:
    if pairs.len > 1:
      # These pairs are candidates.
      for i in 0..<pairs.high:
        let pair1 = pairs[i]
        for j in i..pairs.high:
          let pair2 = pairs[j]
          if pair1[0] != pair2[0] and pair1[0] != pair2[1] and
             pair1[1] != pair2[0] and pair1[1] != pair2[1]:
            # "pair1" and "pair2" have no common state.
            result.add (pair1, pair2)


proc `$`(pairs: MatchingPairs): string =
  ## Return the string representation of two matching pairs.
  "$1 & $2 = $3 & $4".format(pairs[0][0], pairs[0][1], pairs[1][0], pairs[1][1])

echo "For real states:"
for n, pairs in matchingPairs(States):
  echo &"{n+1:2}:  {pairs}"
echo()
echo "For real + fictitious states:"
for n, pairs in matchingPairs(States & Fictitious):
  echo &"{n+1:2}:  {pairs}"
Output:
For real states:
 1:  North Carolina & South Dakota = North Dakota & South Carolina

For real + fictitious states:
 1:  North Carolina & South Dakota = North Dakota & South Carolina
 2:  Kory New & New Kory = New York & Wen Kory
 3:  Kory New & New Kory = New York & York New
 4:  Kory New & New Kory = Wen Kory & York New
 5:  Kory New & New York = New Kory & Wen Kory
 6:  Kory New & New York = New Kory & York New
 7:  Kory New & New York = Wen Kory & York New
 8:  Kory New & Wen Kory = New Kory & New York
 9:  Kory New & Wen Kory = New Kory & York New
10:  Kory New & Wen Kory = New York & York New
11:  Kory New & York New = New Kory & New York
12:  Kory New & York New = New Kory & Wen Kory
13:  Kory New & York New = New York & Wen Kory
14:  New Kory & New York = Wen Kory & York New
15:  New Kory & Wen Kory = New York & York New
16:  New Kory & York New = New York & Wen Kory

Perl

#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };


sub uniq {
    my %uniq;
    undef @uniq{ @_ };
    return keys %uniq
}


sub puzzle {
    my @states = uniq(@_);

    my %pairs;
    for my $state1 (@states) {
        for my $state2 (@states) {
            next if $state1 le $state2;
            my $both = join q(),
                       grep ' ' ne $_,
                       sort split //,
                       lc "$state1$state2";
            push @{ $pairs{$both} }, [ $state1, $state2 ];
        }
    }

    for my $pair (keys %pairs) {
        next if 2 > @{ $pairs{$pair} };

        for my $pair1 (@{ $pairs{$pair} }) {
            for my $pair2 (@{ $pairs{$pair} }) {
                next if 4 > uniq(@$pair1, @$pair2)
                     or $pair1->[0] lt $pair2->[0];

                say join ' = ', map { join ' + ', @$_ } $pair1, $pair2;
            }
        }
    }
}

my @states = ( 'Alabama', 'Alaska', 'Arizona', 'Arkansas',
               'California', 'Colorado', 'Connecticut', 'Delaware',
               'Florida', 'Georgia', 'Hawaii',
               'Idaho', 'Illinois', 'Indiana', 'Iowa',
               'Kansas', 'Kentucky', 'Louisiana',
               'Maine', 'Maryland', 'Massachusetts', 'Michigan',
               'Minnesota', 'Mississippi', 'Missouri', 'Montana',
               'Nebraska', 'Nevada', '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',
             );

my @fictious = ( 'New Kory', 'Wen Kory', 'York New', 'Kory New', 'New Kory' );

say scalar @states, ' states:';
puzzle(@states);

say @states + @fictious, ' states:';
puzzle(@states, @fictious);

Phix

with javascript_semantics
constant states = {"Alabama", "Alaska", "Arizona", "Arkansas", 
                   "California", "Colorado", "Connecticut", "Delaware", 
                   "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", 
                   "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana",
                   "Maine", "Maryland", "Massachusetts", "Michigan", 
                   "Minnesota", "Mississippi", "Missouri", "Montana", 
                   "Nebraska", "Nevada", "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"},
--       extras = {"New Kory", "Wen Kory", "York New", "Kory New", "New Kory"}
         extras = {"Slender Dragon", "Abalamara"}
 
function no_dup(sequence s)
    s = sort(s)
    for i=length(s) to 2 by -1 do
        if s[i]=s[i-1] then
            s[i] = s[$]
            s = s[1..$-1]
        end if
    end for
    return s
end function
 
procedure play(sequence s)
    s = no_dup(deep_copy(s))
    destroy_dict(1) -- empty dict
    for i=1 to length(s)-1 do
        for j=i+1 to length(s) do
            string key = trim(sort(lower(s[i]&s[j])))
            object data = getd(key)
            if data=0 then
                putd(key,{{i,j}})
            else
                for k=1 to length(data) do
                    integer {m,n} = data[k]
                    if m!=i and m!=j and n!=i and n!=j then
                        ?{s[i],s[j],"<==>",s[m],s[n]}
                    end if
                end for
                putd(key,append(deep_copy(data),{i,j}))
            end if
        end for
    end for
end procedure
play(states)
?"==="
play(states&extras)
Output:
{"North Dakota","South Carolina","<==>","North Carolina","South Dakota"}
"==="
{"Alabama","Arkansas","<==>","Abalamara","Kansas"}
{"North Dakota","South Carolina","<==>","North Carolina","South Dakota"}
{"Oregon","Rhode Island","<==>","Ohio","Slender Dragon"}

PicoLisp

(setq *States
   (group
      (mapcar '((Name) (cons (clip (sort (chop (lowc Name)))) Name))
         (quote
            "Alabama" "Alaska" "Arizona" "Arkansas"
            "California" "Colorado" "Connecticut"
            "Delaware"
            "Florida" "Georgia" "Hawaii"
            "Idaho" "Illinois" "Indiana" "Iowa"
            "Kansas" "Kentucky" "Louisiana"
            "Maine" "Maryland" "Massachusetts" "Michigan"
            "Minnesota" "Mississippi" "Missouri" "Montana"
            "Nebraska" "Nevada" "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"
            "New Kory" "Wen Kory" "York New" "Kory New" "New Kory" ) ) ) )

(extract
   '((P)
      (when (cddr P)
         (mapcar
            '((X)
               (cons
                  (cadr (assoc (car X) *States))
                  (cadr (assoc (cdr X) *States)) ) )
            (cdr P) ) ) )
   (group
      (mapcon
         '((X)
            (extract
               '((Y)
                  (cons
                     (sort (conc (copy (caar X)) (copy (car Y))))
                     (caar X)
                     (car Y) ) )
               (cdr X) ) )
         *States ) ) )

Output:

-> ((("North Carolina" . "South Dakota") ("North Dakota" . "South Carolina")))

Prolog

Works with SWI-Prolog. Use of Goedel numbers.

state_name_puzzle :-
	L = ["Alabama", "Alaska", "Arizona", "Arkansas",
	     "California", "Colorado", "Connecticut",
	     "Delaware",
	     "Florida", "Georgia", "Hawaii",
	     "Idaho", "Illinois", "Indiana", "Iowa",
	     "Kansas", "Kentucky", "Louisiana",
	     "Maine", "Maryland", "Massachusetts", "Michigan",
	     "Minnesota", "Mississippi", "Missouri", "Montana",
	     "Nebraska", "Nevada", "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",
	     "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"],

	maplist(goedel, L, R),

	% sort remove duplicates
	sort(R, RS),

	study(RS).

study([]).

study([V-Word|T]) :-
	study_1_Word(V-Word, T, T),
	study(T).


study_1_Word(_, [], _).
study_1_Word(V1-W1, [V2-W2 | T1], T) :-
	TT is V1+V2,
	study_2_Word(W1, W2, TT, T),
	study_1_Word(V1-W1, T1, T).

study_2_Word(_W1, _W2, _TT, []).

study_2_Word(W1, W2, TT, [V3-W3 | T]) :-
	(   W2 \= W3 -> study_3_Word(W1, W2, TT, V3-W3, T); true),
	study_2_Word(W1, W2, TT, T).

study_3_Word(_W1, _W2, _TT, _V3-_W3, []).

study_3_Word(W1, W2, TT, V3-W3, [V4-W4|T]) :-
	TT1 is V3 + V4,
	(   TT1 < TT -> study_3_Word(W1, W2, TT, V3-W3, T)
	;   (TT1 = TT -> ( W4 \= W2 -> format('~w & ~w  with ~w & ~w~n', [W1, W2, W3, W4])
	                               ; true),
           	         study_3_Word(W1, W2, TT, V3-W3, T))
	;   true).

% Compute a Goedel number for the word
goedel(Word, Goedel-A) :-
	name(A, Word),
	downcase_atom(A, Amin),
	atom_codes(Amin, LA),
	compute_Goedel(LA, 0, Goedel).

compute_Goedel([], G, G).

compute_Goedel([32|T], GC, GF) :-
	compute_Goedel(T, GC, GF).

compute_Goedel([H|T], GC, GF) :-
	Ind is H - 97,
	GC1 is GC + 26 ** Ind,
	compute_Goedel(T, GC1, GF).

Output :

  ?- time(state_name_puzzle).
North Carolina & South Dakota  with North Dakota & South Carolina
Kory New & New Kory  with New York & Wen Kory
Kory New & New Kory  with New York & York New
Kory New & New Kory  with Wen Kory & York New
Kory New & New York  with New Kory & Wen Kory
Kory New & New York  with New Kory & York New
Kory New & New York  with Wen Kory & York New
Kory New & Wen Kory  with New Kory & New York
Kory New & Wen Kory  with New Kory & York New
Kory New & Wen Kory  with New York & York New
Kory New & York New  with New Kory & New York
Kory New & York New  with New Kory & Wen Kory
Kory New & York New  with New York & Wen Kory
New Kory & New York  with Wen Kory & York New
New Kory & Wen Kory  with New York & York New
New Kory & York New  with New York & Wen Kory
% 1,076,511 inferences, 1.078 CPU in 1.141 seconds (94% CPU, 998503 Lips)
true .

Python

Translation of: D
from collections import defaultdict

states = ["Alabama", "Alaska", "Arizona", "Arkansas",
"California", "Colorado", "Connecticut", "Delaware", "Florida",
"Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas",
"Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts",
"Michigan", "Minnesota", "Mississippi", "Missouri", "Montana",
"Nebraska", "Nevada", "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",
# Uncomment the next line for the fake states.
# "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"
]

states = sorted(set(states))

smap = defaultdict(list)
for i, s1 in enumerate(states[:-1]):
    for s2 in states[i + 1:]:
        smap["".join(sorted(s1 + s2))].append(s1 + " + " + s2)

for pairs in sorted(smap.itervalues()):
    if len(pairs) > 1:
        print " = ".join(pairs)

Racket

#lang racket
(define states
  (list->set
   (map string-downcase
        '("Alabama" "Alaska" "Arizona" "Arkansas"          
          "California" "Colorado" "Connecticut"
          "Delaware"    
          "Florida" "Georgia" "Hawaii"
          "Idaho" "Illinois" "Indiana" "Iowa"
          "Kansas" "Kentucky" "Louisiana"
          "Maine" "Maryland" "Massachusetts" "Michigan"
          "Minnesota" "Mississippi" "Missouri" "Montana"
          "Nebraska""Nevada" "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"
          ; "New Kory" "Wen Kory" "York New" "Kory New" "New Kory"
          ))))

(define (canon s t) 
  (sort (append (string->list s) (string->list t)) char<? ))

(define seen (make-hash))
(for* ([s1 states] [s2 states] #:when (string<? s1 s2))  
  (define c (canon s1 s2))
  (cond [(hash-ref seen c (λ() (hash-set! seen c (list s1 s2)) #f))
         => (λ(states) (displayln (~v states (list s1 s2))))]))

Output:

'("north dakota" "south carolina") '("north carolina" "south dakota")

Raku

(formerly Perl 6)

Works with: rakudo version 2018.03
my @states = <
    Alabama Alaska Arizona Arkansas California Colorado Connecticut Delaware
    Florida Georgia Hawaii Idaho Illinois Indiana Iowa Kansas Kentucky
    Louisiana Maine Maryland Massachusetts Michigan Minnesota Mississippi
    Missouri Montana Nebraska Nevada 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
>;

say "50 states:";
.say for anastates @states;
 
say "\n54 states:";
.say for sort anastates @states, < New_Kory Wen_Kory York_New Kory_New New_Kory >;

sub anastates (*@states) {
    my @s = @states.unique».subst('_', ' ');
     
    my @pairs = gather for ^@s -> $i {
	for $i ^..^ @s -> $j {
	    take [ @s[$i], @s[$j] ];
	}
    }
     
    my $equivs = hash @pairs.classify: *.lc.comb.sort.join;

    gather for $equivs.values -> @c {
	for ^@c -> $i {
	    for $i ^..^ @c -> $j {
		my $set = set @c[$i].list, @c[$j].list;
		take @c[$i].list.join(', ') ~ ' = ' ~ @c[$j].list.join(', ') if $set == 4;
	    }
	}
    }
}

Output:

50 states:
North Carolina, South Dakota = North Dakota, South Carolina

54 states:
New Kory, Kory New = Wen Kory, York New
New Kory, Wen Kory = York New, Kory New
New Kory, York New = Wen Kory, Kory New
New York, Kory New = New Kory, Wen Kory
New York, Kory New = New Kory, York New
New York, Kory New = Wen Kory, York New
New York, New Kory = Wen Kory, Kory New
New York, New Kory = Wen Kory, York New
New York, New Kory = York New, Kory New
New York, Wen Kory = New Kory, Kory New
New York, Wen Kory = New Kory, York New
New York, Wen Kory = York New, Kory New
New York, York New = New Kory, Kory New
New York, York New = New Kory, Wen Kory
New York, York New = Wen Kory, Kory New
North Carolina, South Dakota = North Dakota, South Carolina

REXX

Code was added to the REXX program to remove dead-end words (state names) that can't possibly be part of
a solution, in particular, words that contain a unique letter (among all the state names).

/*REXX program  (state name puzzle)  rearranges two state's names ──► two new states.   */
!='Alabama,  Alaska, Arizona,  Arkansas, California,    Colorado, Connecticut,       Delaware, Florida, Georgia,',
  'Hawaii,   Idaho,  Illinois, Indiana,  Iowa, Kansas,  Kentucky, Louisiana,  Maine, Maryland, Massachusetts,   ',
  'Michigan, Minnesota, Mississippi, Missouri, Montana, Nebraska, Nevada, 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'
parse arg xtra;    !=! ',' xtra                     /*add optional  (fictitious)  names.*/
@abcU= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';     !=space(!) /*!: the state list, no extra blanks*/
deads=0;    dups=0;    L.=0;     !orig=!;      @@.= /*initialize some REXX variables.   */
z=0                                                 /* [↑]  elide  dend─end (DE) states.*/
    do de=0  for 2;              !=!orig            /*use original state list for each. */
    @.=
        do states=0  by 0  until !==''              /*parse until the cows come home.   */
        parse var !  x  ','  !;       x=space(x)    /*remove all blanks from state name.*/
        if @.x\==''  then do                        /*was state was already specified?  */
                          if de  then iterate       /*don't tell error if doing 2nd pass*/
                          dups=dups + 1             /*bump the duplicate counter.       */
                          say 'ignoring the 2nd naming of the state: '    x;      iterate
                          end
        @.x=x                                       /*indicate this state name exists.  */
        y=space(x,0);    upper y;    yLen=length(y) /*get upper name with no spaces; Len*/
        if de  then do                              /*Is the firstt pass?  Then process.*/
                         do j=1  for yLen           /*see if it's a dead─end state name.*/
                         _=substr(y, j, 1)          /* _:  is some state name character.*/
                         if L._ \== 1  then iterate /*Count ¬ 1?  Then state name is OK.*/
                         say 'removing dead─end state  [which has the letter '   _"]: "  x
                         deads=deads + 1            /*bump number of dead─ends states.  */
                         iterate states             /*go and process another state name.*/
                         end   /*j*/
                    z=z+1                           /*bump counter of the state names.  */
                    #.z=y;  ##.z=x                  /*assign state name;  also original.*/
                    end
               else do k=1  for yLen                /*inventorize letters of state name.*/
                    _=substr(y,k,1);   L._=L._ + 1  /*count each letter in state name.  */
                    end   /*k*/
        end   /*states*/                            /*the index STATES isn't incremented*/
    end       /*de*/
call list                                           /*list state names in order given.  */
                   say z     'state name's(z)                "are useable."
if dups \==0  then say dups  'duplicate of a state's(dups)   'ignored.'
if deads\==0  then say deads 'dead─end state's(deads)        'deleted.'
sols=0                                              /*number of solutions found (so far)*/
say                                                 /*[↑]  look for mix and match states*/
     do j=1  for z     /* ◄──────────────────────────────────────────────────────────┐  */
       do k=j+1  to z                               /* ◄─── state K,  state J  ►─────┘  */
       if #.j<<#.k  then JK=#.j || #.k              /*is the state in the proper order? */
                    else JK=#.k || #.j              /*No,  then use the new state name. */
         do m=1  for z; if m==j | m==k then iterate /*no state  overlaps  are allowed.  */
         if verify(#.m, jk) \== 0      then iterate /*is this state name even possible? */
         nJK=elider(JK, #.m)                        /*a new JK, after eliding #.m chars.*/
           do n=m+1  to z; if n==j | n==k then iterate      /*no overlaps are allowed.  */
           if verify(#.n, nJK) \== 0      then iterate      /*is it possible?           */
           if elider(nJK, #.n) \== ''     then iterate      /*any leftovers letters?    */
           if #.m<<#.n  then MN=#.m || #.n                  /*is it in the proper order?*/
                        else MN=#.n || #.m                  /*we found a new state name.*/
           if @@.JK.MN\=='' | @@.MN.JK\==""  then iterate   /*was it done before?       */
           say 'found: '      ##.j','     ##.k       "  ───►  "        ##.m','      ##.n
           @@.JK.MN=1                            /*indicate this solution as being found*/
           sols=sols+1                           /*bump the number of solutions found.  */
           end   /*n*/
         end     /*m*/
       end       /*k*/
     end         /*j*/
say                                              /*show a blank line for easier reading.*/
if sols==0  then sols= 'No'                      /*use mucher gooder (sic) Englishings. */
say sols  'solution's(sols)    "found."          /*display the number of solutions found*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
elider: parse arg hay,pins                       /*remove letters (pins) from haystack. */
                            do e=1  for length(pins);    p=pos( substr( pins, e, 1),  hay)
                            if p==0  then iterate   ;    hay=overlay(' ', hay, p)
                            end   /*e*/          /* [↑]  remove a letter from haystack. */
        return space(hay, 0)                     /*remove blanks from the haystack.     */
/*──────────────────────────────────────────────────────────────────────────────────────*/
list:   say;   do i=1  for z;   say right(i, 9)   ##.i;   end;            say;      return
s:      if arg(1)==1  then return arg(3);    return word(arg(2) 's', 1)    /*pluralizer.*/
output   when using the default input:
removing dead─end state  [which has the letter  Z]:  Arizona
removing dead─end state  [which has the letter  J]:  New Jersey

        1 Alabama
        2 Alaska
        3 Arkansas
        4 California
        5 Colorado
        6 Connecticut
        7 Delaware
        8 Florida
        9 Georgia
       10 Hawaii
       11 Idaho
       12 Illinois
       13 Indiana
       14 Iowa
       15 Kansas
       16 Kentucky
       17 Louisiana
       18 Maine
       19 Maryland
       20 Massachusetts
       21 Michigan
       22 Minnesota
       23 Mississippi
       24 Missouri
       25 Montana
       26 Nebraska
       27 Nevada
       28 New Hampshire
       29 New Mexico
       30 New York
       31 North Carolina
       32 North Dakota
       33 Ohio
       34 Oklahoma
       35 Oregon
       36 Pennsylvania
       37 Rhode Island
       38 South Carolina
       39 South Dakota
       40 Tennessee
       41 Texas
       42 Utah
       43 Vermont
       44 Virginia
       45 Washington
       46 West Virginia
       47 Wisconsin
       48 Wyoming

48 state names are useable.
2 dead─end states deleted.

found:  North Carolina, South Dakota   ───►   North Dakota, South Carolina

1 solution found.

output when using the input of:   New Kory, Wen Kory, York New, Kory New, New Kory

ignoring the 2nd naming of the state:  New Kory
removing dead─end state  [which has the letter  Z]:  Arizona
removing dead─end state  [which has the letter  J]:  New Jersey

        1 Alabama
        2 Alaska
        3 Arkansas
        4 California
        5 Colorado
        6 Connecticut
        7 Delaware
        8 Florida
        9 Georgia
       10 Hawaii
       11 Idaho
       12 Illinois
       13 Indiana
       14 Iowa
       15 Kansas
       16 Kentucky
       17 Louisiana
       18 Maine
       19 Maryland
       20 Massachusetts
       21 Michigan
       22 Minnesota
       23 Mississippi
       24 Missouri
       25 Montana
       26 Nebraska
       27 Nevada
       28 New Hampshire
       29 New Mexico
       30 New York
       31 North Carolina
       32 North Dakota
       33 Ohio
       34 Oklahoma
       35 Oregon
       36 Pennsylvania
       37 Rhode Island
       38 South Carolina
       39 South Dakota
       40 Tennessee
       41 Texas
       42 Utah
       43 Vermont
       44 Virginia
       45 Washington
       46 West Virginia
       47 Wisconsin
       48 Wyoming
       49 New Kory
       50 Wen Kory
       51 York New
       52 Kory New

52 state names are useable.
1 duplicate of a state ignored.
2 dead─end states deleted.

found:  New York, New Kory   ───►   Wen Kory, York New
found:  New York, New Kory   ───►   Wen Kory, Kory New
found:  New York, New Kory   ───►   York New, Kory New
found:  New York, Wen Kory   ───►   New Kory, York New
found:  New York, Wen Kory   ───►   New Kory, Kory New
found:  New York, Wen Kory   ───►   York New, Kory New
found:  New York, York New   ───►   New Kory, Wen Kory
found:  New York, York New   ───►   New Kory, Kory New
found:  New York, York New   ───►   Wen Kory, Kory New
found:  New York, Kory New   ───►   New Kory, Wen Kory
found:  New York, Kory New   ───►   New Kory, York New
found:  New York, Kory New   ───►   Wen Kory, York New
found:  North Carolina, South Dakota   ───►   North Dakota, South Carolina
found:  New Kory, Wen Kory   ───►   York New, Kory New
found:  New Kory, York New   ───►   Wen Kory, Kory New
found:  New Kory, Kory New   ───►   Wen Kory, York New

16 solutions found.

Ruby

Translation of: Tcl
require 'set'

# 26 prime numbers
Primes = [ 2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 
          43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
States = [
    "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado",
    "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
    "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine",
    "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi",
    "Missouri", "Montana", "Nebraska", "Nevada", "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"
]

def print_answer(states)
  # find goedel numbers for all pairs of states
  goedel = lambda {|str| str.chars.map {|c| Primes[c.ord - 65]}.reduce(:*)}
  pairs = Hash.new {|h,k| h[k] = Array.new}
  map = states.uniq.map {|state| [state, goedel[state.upcase.delete("^A-Z")]]}
  map.combination(2) {|(s1,g1), (s2,g2)| pairs[g1 * g2] << [s1, s2]}

  # find pairs without duplicates
  result = []
  pairs.values.select {|val| val.length > 1}.each do |list_of_pairs|
    list_of_pairs.combination(2) do |pair1, pair2|
      if Set[*pair1, *pair2].length == 4
        result << [pair1, pair2]
      end
    end
  end

  # output the results
  result.each_with_index do |(pair1, pair2), i| 
    puts "%d\t%s\t%s" % [i+1, pair1.join(', '), pair2.join(', ')]
  end
end

puts "real states only"
print_answer(States)
puts ""
puts "with fictional states"
print_answer(States + ["New Kory", "Wen Kory", "York New", "Kory New", "New Kory"])

outputs

real states only
1       North Carolina, South Dakota    North Dakota, South Carolina

with fictional states
1       New York, New Kory      Wen Kory, York New
2       New York, New Kory      Wen Kory, Kory New
3       New York, New Kory      York New, Kory New
4       New York, Wen Kory      New Kory, York New
5       New York, Wen Kory      New Kory, Kory New
6       New York, Wen Kory      York New, Kory New
7       New York, York New      New Kory, Wen Kory
8       New York, York New      New Kory, Kory New
9       New York, York New      Wen Kory, Kory New
10      New York, Kory New      New Kory, Wen Kory
11      New York, Kory New      New Kory, York New
12      New York, Kory New      Wen Kory, York New
13      New Kory, Wen Kory      York New, Kory New
14      New Kory, York New      Wen Kory, Kory New
15      New Kory, Kory New      Wen Kory, York New
16      North Carolina, South Dakota    North Dakota, South Carolina

Rust

Translation of: Kotlin
use std::collections::HashMap;

fn solve(states: Vec<&str>) {
    let mut dict = HashMap::new();
    for state in states {
        let key = state.to_lowercase().replace(" ", "");
        if !dict.contains_key(&key) {
            dict.insert(key, state);
        }
    }
    let keys: Vec<&String> = dict.keys().collect();
    let mut solutions: Vec<String> = vec![];
    let mut duplicates: Vec<String> = vec![];
    for i in 0..keys.len() {
        for j in i + 1..keys.len() {
            let len = keys[i].len() + keys[j].len();
            let mut chars: Vec<char> = (String::new() + keys[i] + keys[j]).chars().collect();
            chars.sort();
            let combined: String = chars.into_iter().collect();
            for k in 0..keys.len() {
                for m in k + 1..keys.len() {
                    if k == i || k == j || m == i || m == j {
                        continue;
                    }
                    let len2 = keys[k].len() + keys[m].len();
                    if len2 != len {
                        continue;
                    }
                    let mut chars2 = (String::new() + keys[k] + keys[m])
                        .chars()
                        .collect::<Vec<char>>();
                    chars2.sort();
                    let combined2: String = chars2.into_iter().collect();
                    if combined == combined2 {
                        let f1 = format!("{} + {}", dict[keys[i]], dict[keys[j]]);
                        let f2 = format!("{} + {}", dict[keys[k]], dict[keys[m]]);
                        let f3 = format!("{f1} = {f2}");
                        if duplicates.contains(&f3) {
                            continue;
                        }
                        solutions.push(f3);
                        let f4 = format!("{f2} = {f1}");
                        duplicates.push(f4);
                    }
                }
            }
        }
    }
    solutions.sort();
    for (i, sol) in solutions.iter().enumerate() {
        println!("{:>2}  {}", i + 1, sol);
    }
}

fn main() {
    let mut states = [
        "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut",
        "Delaware", "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa",
        "Kansas", "Kentucky", "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan",
        "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
        "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",].to_vec();
    println!("Real states only:");
    solve(states.clone());
    let mut fictitious = ["New Kory", "Wen Kory", "York New", "Kory New", "New Kory"].to_vec();
    println!("\nReal and fictitious states:");
    states.append(&mut fictitious);
    solve(states.clone());
}
Output:
Real states only:
 1  North Carolina + South Dakota = North Dakota + South Carolina

Real and fictitious states:
 1  Kory New + New Kory = New York + Wen Kory
 2  Kory New + New Kory = York New + New York
 3  Kory New + New Kory = York New + Wen Kory
 4  Kory New + New York = New Kory + Wen Kory
 5  Kory New + New York = York New + New Kory
 6  Kory New + New York = York New + Wen Kory
 7  Kory New + Wen Kory = New York + New Kory
 8  Kory New + Wen Kory = York New + New Kory
 9  Kory New + Wen Kory = York New + New York
10  Kory New + York New = New Kory + Wen Kory
11  Kory New + York New = New York + New Kory
12  Kory New + York New = New York + Wen Kory
13  South Carolina + North Dakota = South Dakota + North Carolina
14  York New + New Kory = New York + Wen Kory
15  York New + New York = New Kory + Wen Kory
16  York New + Wen Kory = New York + New Kory

Scala

object StateNamePuzzle extends App {
  // Logic:
  def disjointPairs(pairs: Seq[Set[String]]) =
    for (a <- pairs; b <- pairs; if a.intersect(b).isEmpty) yield Set(a,b)

  def anagramPairs(words: Seq[String]) =
    (for (a <- words; b <- words; if a != b) yield Set(a, b)) // all pairs
    .groupBy(_.mkString.toLowerCase.replaceAll("[^a-z]", "").sorted) // grouped anagram pairs
    .values.map(disjointPairs).flatMap(_.distinct) // unique non-overlapping anagram pairs

  // Test:
  val states = List(
    "New Kory", "Wen Kory", "York New", "Kory New", "New Kory",
    "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado",
    "Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
    "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine",
    "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi",
    "Missouri", "Montana", "Nebraska", "Nevada", "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"
  )

  println(anagramPairs(states).map(_.map(_ mkString " + ") mkString " = ") mkString "\n")
}
Output:
New Kory + Wen Kory = York New + Kory New
New Kory + Wen Kory = York New + New York
New Kory + Wen Kory = Kory New + New York
New Kory + York New = Wen Kory + Kory New
New Kory + York New = Wen Kory + New York
New Kory + York New = Kory New + New York
New Kory + Kory New = Wen Kory + York New
New Kory + Kory New = Wen Kory + New York
New Kory + Kory New = York New + New York
New Kory + New York = Wen Kory + York New
New Kory + New York = Wen Kory + Kory New
New Kory + New York = York New + Kory New
Wen Kory + York New = Kory New + New York
Wen Kory + Kory New = York New + New York
Wen Kory + New York = York New + Kory New
North Carolina + South Dakota = North Dakota + South Carolina

Tcl

package require Tcl 8.5
# Gödel number generator
proc goedel s {
    set primes {
	2 3 5 7 11 13 17 19 23 29 31 37 41
	43 47 53 59 61 67 71 73 79 83 89 97 101
    }
    set n 1
    foreach c [split [string toupper $s] ""] {
	if {![string is alpha $c]} continue
	set n [expr {$n * [lindex $primes [expr {[scan $c %c] - 65}]]}]
    }
    return $n
}
# Calculates the pairs of states
proc groupStates {stateList} {
    set stateList [lsort -unique $stateList]
    foreach state1 $stateList {
	foreach state2 $stateList {
	    if {$state1 >= $state2} continue
	    dict lappend group [goedel $state1$state2] [list $state1 $state2]
	}
    }
    foreach g [dict values $group] {
	if {[llength $g] > 1} {
	    foreach p1 $g {
		foreach p2 $g {
		    if {$p1 < $p2 && [unshared $p1 $p2]} {
			lappend result [list $p1 $p2]
		    }
		}
	    }
	}
    }
    return $result
}
proc unshared args {
    foreach p $args {
	foreach a $p {incr s($a)}
    }
    expr {[array size s] == [llength $args]*2}
}
# Pretty printer for state name pair lists
proc printPairs {title groups} {
    foreach group $groups {
	puts "$title Group #[incr count]"
	foreach statePair $group {
	    puts "\t[join $statePair {, }]"
	}
    }
}

set realStates {
    "Alabama" "Alaska" "Arizona" "Arkansas" "California" "Colorado"
    "Connecticut" "Delaware" "Florida" "Georgia" "Hawaii" "Idaho" "Illinois"
    "Indiana" "Iowa" "Kansas" "Kentucky" "Louisiana" "Maine" "Maryland"
    "Massachusetts" "Michigan" "Minnesota" "Mississippi" "Missouri" "Montana"
    "Nebraska" "Nevada" "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"
}
printPairs "Real States" [groupStates $realStates]
set falseStates {
    "New Kory" "Wen Kory" "York New" "Kory New" "New Kory"
}
printPairs "Real and False States" [groupStates [concat $realStates $falseStates]]

Output:

Real States Group #1
	North Carolina, South Dakota
	North Dakota, South Carolina
Real and False States Group #1
	Kory New, New Kory
	New York, Wen Kory
Real and False States Group #2
	Kory New, New Kory
	New York, York New
Real and False States Group #3
	Kory New, New Kory
	Wen Kory, York New
Real and False States Group #4
	Kory New, New York
	New Kory, Wen Kory
Real and False States Group #5
	Kory New, New York
	New Kory, York New
Real and False States Group #6
	Kory New, New York
	Wen Kory, York New
Real and False States Group #7
	Kory New, Wen Kory
	New Kory, New York
Real and False States Group #8
	Kory New, Wen Kory
	New Kory, York New
Real and False States Group #9
	Kory New, Wen Kory
	New York, York New
Real and False States Group #10
	Kory New, York New
	New Kory, New York
Real and False States Group #11
	Kory New, York New
	New Kory, Wen Kory
Real and False States Group #12
	Kory New, York New
	New York, Wen Kory
Real and False States Group #13
	New Kory, New York
	Wen Kory, York New
Real and False States Group #14
	New Kory, Wen Kory
	New York, York New
Real and False States Group #15
	New Kory, York New
	New York, Wen Kory
Real and False States Group #16
	North Carolina, South Dakota
	North Dakota, South Carolina

Wren

Translation of: Kotlin
Library: Wren-str
Library: Wren-sort
Library: Wren-fmt
import "./str" for Str
import "./sort" for Sort
import "./fmt" for Fmt

var solve = Fn.new { |states|
    var dict = {}
    for (state in states) {
        var key = Str.lower(state).replace(" ", "")
        if (!dict[key]) dict[key] = state
    }
    var keys = dict.keys.toList
    Sort.quick(keys)
    var solutions = []
    var duplicates = []
    for (i in 0...keys.count) {
        for (j in i+1...keys.count) {
            var len = keys[i].count + keys[j].count
            var chars = (keys[i] + keys[j]).toList
            Sort.quick(chars)
            var combined = chars.join()
            for (k in 0...keys.count) {
                for (l in k+1...keys.count) {
                    if (k != i && k != j && l != i && l != j) {
                        var len2 = keys[k].count + keys[l].count
                        if (len2 == len) {
                            var chars2 = (keys[k] + keys[l]).toList
                            Sort.quick(chars2)
                            var combined2 = chars2.join()
                            if (combined == combined2) {
                                var f1 = "%(dict[keys[i]]) + %(dict[keys[j]])"                   
                                var f2 = "%(dict[keys[k]]) + %(dict[keys[l]])"
                                var f3 = "%(f1) = %(f2)"
                                if (!duplicates.contains(f3)) {
                                    solutions.add(f3)
                                    var f4 = "%(f2) = %(f1)"
                                    duplicates.add(f4)
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    Sort.quick(solutions)
    var i = 0
    for (sol in solutions) {
        Fmt.print("$2d  $s", i + 1, sol)
        i = i + 1
    }
}

var states = [
    "Alabama", "Alaska", "Arizona", "Arkansas",
    "California", "Colorado", "Connecticut",
    "Delaware",
    "Florida", "Georgia", "Hawaii",
    "Idaho", "Illinois", "Indiana", "Iowa",
    "Kansas", "Kentucky", "Louisiana",
    "Maine", "Maryland", "Massachusetts", "Michigan",
    "Minnesota", "Mississippi", "Missouri", "Montana",
    "Nebraska", "Nevada", "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"
]
System.print("Real states only:")
solve.call(states)
System.print()
var fictitious = [ "New Kory", "Wen Kory", "York New", "Kory New", "New Kory"  ]
System.print("Real and fictitious states:")
solve.call(states + fictitious)
Output:
Real states only:
 1  North Carolina + South Dakota = North Dakota + South Carolina

Real and fictitious states:
 1  Kory New + New Kory = New York + Wen Kory
 2  Kory New + New Kory = New York + York New
 3  Kory New + New Kory = Wen Kory + York New
 4  Kory New + New York = New Kory + Wen Kory
 5  Kory New + New York = New Kory + York New
 6  Kory New + New York = Wen Kory + York New
 7  Kory New + Wen Kory = New Kory + New York
 8  Kory New + Wen Kory = New Kory + York New
 9  Kory New + Wen Kory = New York + York New
10  Kory New + York New = New Kory + New York
11  Kory New + York New = New Kory + Wen Kory
12  Kory New + York New = New York + Wen Kory
13  New Kory + New York = Wen Kory + York New
14  New Kory + Wen Kory = New York + York New
15  New Kory + York New = New York + Wen Kory
16  North Carolina + South Dakota = North Dakota + South Carolina

zkl

Translation of: Python
#<<<  // here doc
states:=("Alabama, Alaska, Arizona, Arkansas,
   California, Colorado, Connecticut, Delaware, Florida,
   Georgia, Hawaii, Idaho, Illinois, Indiana, Iowa, Kansas,
   Kentucky, Louisiana, Maine, Maryland, Massachusetts,
   Michigan, Minnesota, Mississippi, Missouri, Montana,
   Nebraska, Nevada, 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"
   /* Uncomment the next line for the fake states. */
   # ",New Kory, Wen Kory, York New, Kory New, New Kory"
#<<<
).split(",").apply("strip");

smap:=Dictionary();
Utils.Helpers.pickNFrom(2,states).apply2('wrap(ss){ // 1225 combinations
   key:=(ss.concat()).toLower().sort()-" ";
   smap[key]=smap.find(key,List()).append(ss.concat(" + "));
});
 
foreach pairs in (smap.values){ // 1224 keys
//    pairs=Utils.Helpers.listUnique(pairs);  // eliminate dups
    if(pairs.len()>1)
        println(pairs.concat(" = ")) }
Output:
North Carolina + South Dakota = North Dakota + South Carolina