Tengo una matriz de códigos postales (de varios países) de este formato:
["100-1001","102-1000","102-1001","102-1002","100-1002","111","112","102-1003","113"]
Tendré que inferir rangos de estos números en el formato de salida de:
[[upper1,lower1],[upper2,lower2]]
Para el ejemplo anterior esto sería:
[["100-1001","100-1002"]["102-1000","102-1003"]["111","113"]]
¿Hay una mejor manera que convertir todo en números planos, eliminando los delimitadores, infiriendo sus rangos y luego volviendo a agregar delimitadores?
Actualmente tengo esta lógica para códigos postales sin guión:
getRanges(zipCodes) { zipCodes.sort(); let length = 1; let ranges = []; for (let i = 1; i <= zipCodes.length; i++) { if (i == zipCodes.length || zipCodes[i] - zipCodes[i - 1] != 1) { if (length == 1) { let upper = lower = zipCodes[i - length]; ranges.push({lower, upper}); } else { let lower = zipCodes[i - length]; let upper = zipCodes[i - 1]; ranges.push({lower, upper}); } length = 1; } else { length++; } } return ranges; }Pero creo que la sobrecarga adicional de eliminar y volver a agregar delimitadores podría evitarse si hubiera una mejor manera de analizar los rangos. gracias de antemano
Una solución simple sería convertir la entrada en una lista de number,string , ordenar/clasificar según los números y finalmente extraer las cadenas del resultado:
function getRanges(arr) { let pairs = arr.map(s => [ Number(s.replace(/\D+/g, '')), s ]) pairs.sort((a, b) => a[0] - b[0]) let ranges = [], last = null for (let p of pairs) { if (last && last[1][0] === p[0] - 1) last[1] = p else ranges.push(last = [p, p]) } return ranges.map(r => [r[0][1], r[1][1]]) } const zipCodes = [ "100-1000", "100-1001", "100-1002", "100-1003", "100-1005", "200-1000", "200-1001", "200-1002", "200-1006", "111", "112", "114", "115", "116", ] console.log(getRanges(zipCodes))La función de clasificación también puede funcionar con cadenas. Entonces, sin eliminar el - esto ordenará la matriz de códigos postales y los agrupará por pares:
function getRanges(zipCodes) { zipCodes.sort(); let ranges = []; for (let i = 0; i <= zipCodes.length - 1; i += 2) { if (zipCodes[i + 1]) { let lower = zipCodes[i]; let upper = zipCodes[i + 1]; ranges.push({lower, upper}); } else { let upper = lower = zipCodes[i]; ranges.push({lower, upper}); } } return ranges; } const zipCodes = ["100-1001", "102-1000", "102-1001", "102-1002", "100-1002", "111", "112", "113"]; const result = getRanges(zipCodes); console.log(result);Actualización: este código no resuelve los requisitos de OP, pero varias personas lo votaron a favor, ya que ordena y agrupa los códigos postales. (Creo que varias personas, incluyéndome a mí, entendieron mal cómo se suponía que debía llevarse a cabo la agrupación).
La forma correcta es la respuesta de georg y la única mejora en la que pensaría es ordenar antes de hacer el map real para que devuelva el mismo orden que la solicitud original. De lo contrario, no puedo pensar en una mejor implementación, así que dejaré mi código original que fue votado a favor si alguien lo encuentra útil.