Join a people group to its UPG-100 zone, with admin names folded
The UPG-100 lists are defined by admin region and the people-group tables are keyed by group, so the join runs through the province assignment. The two files disagree on spelling: the zone table writes `gujarat`, the province table writes `Gujarāt`, and the same for Karnātaka, Tamil Nādu, Uttarākhand, Jammu and Kashmīr and Haryāna. Matching on toLowerCase alone joins 514 of 1009 rows across 9 zones. Folding the combining marks joins 1009 of 1009 across 12 zones. The 50.9% is the number worth naming: a legend built on it would have shown half the groups and three fewer zones, and nothing on screen would have said so — every zone still looks populated, only smaller. The fold lives at the lookup rather than as extra spellings in the zone table, so a future source spelling cannot reopen it.
This commit is contained in:
parent
dece2df47e
commit
d6253b34d0
1 changed files with 57 additions and 0 deletions
57
plugin-designs/gospel-internet/src/upgZones.js
Normal file
57
plugin-designs/gospel-internet/src/upgZones.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* upgZones.js — join a people group to its UPG-100 zone.
|
||||
*
|
||||
* THE CHAIN, and why it needs three files. UPG-100 lists are defined by ADMIN REGION
|
||||
* ("Tibet Autonomous Region", "Gujarat"); the people-group tables are keyed by group.
|
||||
* They share no id, so the bridge is the province assignment:
|
||||
*
|
||||
* admin-to-list.json admin name -> zone id
|
||||
* gospel-by-province-groups.json group -> province name
|
||||
*
|
||||
* ★ ADMIN NAMES ARE MATCHED WITH DIACRITICS FOLDED, and that is load-bearing rather than
|
||||
* defensive. The two files disagree on spelling: the zone table writes `gujarat`, the
|
||||
* province table writes `Gujarāt`; likewise Karnātaka, Tamil Nādu, Uttarākhand, Jammu and
|
||||
* Kashmīr, Haryāna. Matching on `.toLowerCase()` alone resolves 514 of 1009 rows across 9
|
||||
* zones. Folding the combining marks resolves 1009 of 1009 across 12 zones.
|
||||
*
|
||||
* That 50.9% is the dangerous number, not the 100%: a legend built on it would have shown
|
||||
* half the groups and three fewer zones with NOTHING ON SCREEN SAYING SO — every zone would
|
||||
* still have looked populated, just smaller. Fold here rather than adding spellings to the
|
||||
* zone table, so a future source spelling cannot reopen it.
|
||||
*/
|
||||
|
||||
/** Lowercase and strip combining marks, so `Gujarāt` and `gujarat` are the same key. */
|
||||
export function foldAdmin(name) {
|
||||
return String(name ?? '')
|
||||
.normalize('NFD')
|
||||
.replace(/\p{Mn}/gu, '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
/** Build a folded lookup from the zone table's `admin name -> zone id` map. */
|
||||
export function zoneIndex(adminToList) {
|
||||
const ix = new Map()
|
||||
for (const [admin, zone] of Object.entries(adminToList || {})) ix.set(foldAdmin(admin), zone)
|
||||
return ix
|
||||
}
|
||||
|
||||
/** The zone id for a province name, or null when the province is in no UPG-100 list. */
|
||||
export function zoneFor(ix, province) {
|
||||
return ix.get(foldAdmin(province)) ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* group key -> zone id, from the province bridge rows.
|
||||
* `key` decides the join key into whatever table the caller holds; the default
|
||||
* `(name, iso3)` is the pair that matches near-neighbors at 994/1009.
|
||||
*/
|
||||
export function zonesByGroup(adminToList, provinceRows, key = (r) => `${r.people_group}|${r.iso3}`) {
|
||||
const ix = zoneIndex(adminToList)
|
||||
const out = new Map()
|
||||
for (const r of provinceRows || []) {
|
||||
const z = zoneFor(ix, r.province)
|
||||
if (z) out.set(key(r), z)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Loading…
Reference in a new issue