Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@okunishinishi
Last active November 27, 2017 02:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okunishinishi/0ff3e169031445ec7575d4ac1c9d0716 to your computer and use it in GitHub Desktop.
Save okunishinishi/0ff3e169031445ec7575d4ac1c9d0716 to your computer and use it in GitHub Desktop.
Gale–Shapley algorithm for Stable marriage problem
#!/usr/bin/env node
/**
* Gale–Shapley algorithm for Stable marriage problem
*
* https://en.wikipedia.org/wiki/Stable_marriage_problem
* http://toyokeizai.net/articles/-/11584
*/
'use strict'
const shuffle = require('shuffle-array')
function defineMembers (memberCount = 10) {
const men = shuffle(new Array(memberCount).fill(null).map((_, i) => ({
name: `man#${i}`,
rejectedBy: [],
likes: []
})))
const women = shuffle(new Array(memberCount).fill(null).map((_, i) => ({
name: `woman#${i}`,
proposedBy: [],
keeps: null,
likes: []
})))
for (const m of men) {
m.likes = shuffle(women).map(({name}) => name)
}
for (const w of women) {
w.likes = shuffle(men).map(({name}) => name)
}
return {men, women}
}
const memberCount = 10
const {men, women} = defineMembers(memberCount)
const menByName = Object.assign({}, ...men.map((man) => ({
[man.name]: man
})))
const womenByName = Object.assign({}, ...women.map((woman) => ({
[woman.name]: woman
})))
for (let round = 0; round < 4; round++) {
for (const m of men) {
const isKept = women.some(({keeps}) => keeps === m.name)
if (!isKept) {
const best = m.likes.find((name) => !m.rejectedBy.includes(name))
if (best) {
womenByName[best].proposedBy.push(m.name)
}
}
}
for (const w of women) {
const [best, ...notGoodEnough] = w.proposedBy.sort((a, b) =>
w.likes.indexOf(a) - w.likes.indexOf(b)
)
w.keeps = best || null
for (const n of notGoodEnough) {
menByName[n].rejectedBy.push(w.name)
}
}
}
{
const couples = women
.map(({name, keeps}) => keeps ? [name, keeps] : null)
.filter(Boolean)
.map(([wName, mName]) => [
womenByName[wName],
menByName[mName]
])
const successCount = couples.length
const failureCount = memberCount - successCount
console.log(`${successCount} success, ${failureCount} failure`)
console.log(
couples.map(([w, m]) => [
w.name, w.likes.indexOf(m.name), m.name, m.likes.indexOf(w.name)
])
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment