Determinar rangos de una lista de valores

18

Dada una lista sin clasificar de enteros positivos únicos, genera la lista más corta de los rangos más largos posibles de enteros secuenciales.

ENTRADA

  • Una lista sin clasificar de enteros positivos únicos
    • p.ej 9 13 3 11 8 4 10 15
  • La entrada puede tomarse de cualquiera de los siguientes:
    • stdin
    • argumentos de línea de comandos
    • argumentos de función

SALIDA

  • Una lista ordenada de rangos o valores individuales impresos en una línea para stdout o la salida similar más cercana a su idioma.
    • Si hay dos o más enteros secuenciales (secuenciales por valor, no por ubicación en la lista), se denotarán como un rango inclusivo usando -, por ejemplo 8-11
    • Todos los demás enteros se imprimen simplemente sin otra notación.
    • Un solo espacio delimitará la salida
  • Los números que no están presentes en la entrada no deben estar en la salida, por ejemplo, 3 5 6no se pueden acortar 3-6porque 4no están presentes

EJEMPLOS

Exitoso:

 IN> 9 13 3 11 8 4 10 15 6
OUT> 3-4 6 8-11 13 15

 IN> 11 10 6 9 13 8 3 4 15
OUT> 3-4 6 8-11 13 15

 IN> 5 8 3 2 6 4 7 1
OUT> 1-8

 IN> 5 3 7 1 9
OUT> 1 3 5 7 9

Incorrecto:

 IN> 9 13 3 11 8 4 10 15
OUT> 3-15

El rango contiene valores que no están en la entrada

 IN> 9 13 3 11 8 4 10 15
OUT> 3 4 8 9 10 11 13 15

Todos los valores secuenciales deben representarse como un rango

 IN> 9 13 3 11 8 4 10 15
OUT> 3-4 8-9 10-11 13 15

Rango dividido, 8-9y 10-11debe ser8-11

 IN> 9 13 3 11 8 4 10 15
OUT> 8-9 13 10-11 3-4 15

Salida no ordenada correctamente

REGLAS

PUNTUACIÓN

  • Menos bytes gana
Corey Ogburn
fuente
1
La primera oración es realmente confusa. Recomiendo decir "generar la lista más corta de los rangos más largos posibles de enteros secuenciales". De lo contrario, buen desafío!
Nathan Merrill
2
Estoy bastante seguro de que hemos tenido este desafío antes, pero no se me ocurren los términos de búsqueda correctos. Alguien recuerda?
xnor
44
@CoreyOgburn Por cierto, ¿qué te impulsó a publicar en PPCG? Estamos tratando de averiguar qué nos dieron un montón de nuevos usuarios a entrar.
XNOR
2
@xnor He estado vigilando el sitio durante meses. Ninguno de los idiomas que uso suele ser un buen candidato para las respuestas y nunca tuve una pregunta para publicar hasta hoy.
Corey Ogburn
1
@xnor: Es similar a la lista de tareas de Maltysen, pero no idéntica.
Alex A.

Respuestas:

9

Python 2, 123120 bytes

N=sorted(map(int,raw_input().split(' ')));print(''.join((''if n+1in N else'-'+`n`)if n-1in N else' '+`n`for n in N)[1:])

Si la entrada puede ser una lista como argumento de función, entonces (gracias mbomb007 y xnor por los condicionales)

93 90 81 bytes

def f(N):print''.join((' '+`n`,`-n`*-~-(n+1in N))[n-1in N]for n in sorted(N))[1:]

(77 bytes si el espacio en blanco inicial es aceptable; descarte el final [1:])

Ruth Franklin
fuente
Puede cambiar str(n)a `n`para guardar algunos bytes, si cambia a Python 2.
mbomb007
También puede crear una función que tome una lista como entrada en lugar de usar raw_input(), y puede cambiar '-'+`n`a `-n`. Y como ahora está usando Python 2, puede eliminar los paréntesis después de print.
mbomb007
Generar la cuerda pieza por pieza es inteligente. Para guardar bytes, generalmente es más corto hacer condicionales por selección de lista o aritmética, como def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](que se puede jugar más).
xnor
Es posible que pueda usar en set(N)lugar de sorted(N); esto iterará correctamente de menor a menor cuando use cPython, pero no se garantiza que funcione para todas las implementaciones, por lo que hay algunas dudas sobre si esto es válido o no.
KSab
6

JavaScript (ES6): 171 154 140 137 bytes

¡Gracias edc65 y vihan1086 por los consejos! [...n]es muy agradable pero no funciona en estos casos debido a números de varios dígitos.

f=n=>{s=e=o='';n.split` `.map(Number).sort((a,b)=>a-b).map(v=>{s=s||v;if(e&&v>e+1){o+=`${s<e?s+'-'+e:s} `;s=v}e=v});return o+(s<e?s+'-'+e:e)}

Variantes ES5, 198 184 183 174 bytes

f=function(n){s=e=o='';n.split(' ').map(Number).sort(function(a,b){return a-b}).map(function(v){s=s||v;if(e&&v>e+1){o+=(s<e?s+'-'+e:s)+' ';s=v}e=v});return o+(s<e?s+'-'+e:e)}

rink.attendant.6
fuente
n.split sin paréntesis es totalmente nuevo para mí! Pero [...n]es mejor
edc65
@ edc65 Gracias, nunca pensé en desempacar la cadena así.
rink.attendant.6
Eche un vistazo a este codegolf.stackexchange.com/questions/37624/…
edc65
... pero ... ¿funciona con alguno de los ejemplos? hay números de varios dígitos, por lo que necesita una división en un "" (espacio en blanco) no "" (cadena vacía). Probablemente te di el consejo equivocado
edc65
@ edc65 Pensé que algo parecía diferente, luego me di cuenta de que los casos de prueba fallaron. Aún así es bueno aprender algo nuevo
rink.attendant.6
4

Ruby, 86 84 bytes

s=->*a{puts a.sort.slice_when{|i,j|i+1!=j}.map{|e|e.size<2?e:[e[0],e[-1]]*"-"}*" "}

# demo
s[9, 13, 3, 11, 8, 4, 10, 15, 6]
# => 3-4 6 8-11 13 15

Esta es una versión ligeramente golfizada de un ejemplo en los documentos para slice_when .

steenslag
fuente
4

CJam, 35 bytes

l~${__0=f-ee::=0+0#/((oW>Wf*S+oe_}h

Pruébelo en línea en el intérprete de CJam .

Cómo funciona

l~$     e# Read a line from STDIN, evaluate it and sort the result.
{       e# Do:
  _     e#   Push a copy of the array.
  _0=f- e#   Subtract the first element from all array elements.
  ee    e#   Enumerate the differences: [0 1 4] -> [[0 0] [1 1] [2 4]]
  ::=   e#   Vectorized quality: [i j] -> (i == j)
  0+    e#   Append a zero.
  0#    e#   Push the first index of 0.
  /     e#   Split the array into chunks of that size.
  (     e#   Shift out the first chunk.
  (o    e#   Print its first element.
  W>    e#   Discard all remaining elements (if any) except the last.
  Wf*   e#   Multiply all elements of the remainder by -1.
  S+o   e#   Append a space and print.
  e_    e#   Flatten the rest of the array.
}h      e# Repeat while the array is non-empty.
Dennis
fuente
4

Ruby, 70 bytes

Problemas como estos tienden a hacer que revise la API de Ruby para ver los métodos adecuados, y hoy descubrí uno nuevo: Array#slice_whenrecientemente introducido en Ruby v2.2 y aparentemente destinado a esta situación exacta :)

f=->a{puts a.sort.slice_when{|i,j|j-i>1}.map{|x|x.minmax.uniq*?-}*' '}

Después de ordenar y dividir adecuadamente la matriz, toma cada sub-matriz y crea una cadena a partir del elemento más alto y más bajo, y luego une toda esta matriz en una cadena.

Ejemplo:

f.call [9,13,3,11,8,4,10,15,6] huellas dactilares 3-4 6 8-11 13 15

daniero
fuente
4

SWI-Prolog, 165 162 159 bytes

b(Z,C,[D|E]):-Z=[A|B],(A=:=D+1,(B=[],put(45),print(A);b(B,C,[A,D|E]));(E=[],tab(1),print(A);writef('-%t %t',[D,A])),b(B,A,[A]));!.
a(A):-sort(A,B),b(B,_,[-1]).

Bastante mal pero, de nuevo, Prolog es un lenguaje de golf terrible

Ejemplo: a([9,13,3,11,8,4,10,15,6]).salidas3-4 6 8-11 13 15

Fatalizar
fuente
3

CJam, 38 33 bytes

Nueva versión, usando ideas y fragmentos de código sugeridos por @Dennis:

l~$_,,.-e`{~T+\_T+:T;(_2$+W*Q?S}/

Pruébalo en línea

El formato de entrada es una matriz CJam entre corchetes.

La idea básica aquí es que primero resto una secuencia monotónica de la secuencia de entrada ordenada:

3  4  8  9 10 11 13 15
0  1  2  3  4  5  6  7  (-)
----------------------
3  3  6  6  6  6  7  8

En esta diferencia, los valores que forman parte del mismo intervalo tienen el mismo valor. La aplicación del operador CJam RLE a esta diferencia enumera directamente los intervalos.

Los valores secuenciales restados deben agregarse nuevamente durante la salida. No estoy del todo contento con cómo se hace eso en mi código. Sospecho que podría guardar algunos bytes con una forma más elegante de entregar eso.

Para generar la salida de los intervalos, esto utiliza la idea de Dennis de generar un número negativo para el valor final, que se encarga de producir un -, y también simplifica la lógica porque solo se necesita agregar / omitir un valor dependiendo del tamaño del intervalo .

Explicación:

l~    Get input.
$     Sort it.
_,,   Create monotonic sequence of same length.
.-    Calculate vector difference between the two.
e`    Calculate RLE of difference vector.
{     Loop over entries in RLE.
  ~     Unpack the RLE entry, now have length/value on stack.
  T+    Add position to get original value for start of interval.
  \     Bring length of interval to top of stack.
  _T+:T;  Add length of interval to variable T, which tracks position.
  (     Decrement interval length.
  _     Copy it, we need it once for calculating end value, once for ternary if condition.
  2$    Copy interval start value to top...
  +     ... and add interval length - 1 to get end value.
  W*    Negate end value.
  Q?    Output end value if interval length was > 1, empty string otherwise.
  S     Add a space.
}%    End loop.
Reto Koradi
fuente
¡Es un uso inteligente de RLE! Al tomar prestado el manejo de rango y el formato de entrada de mi respuesta, puede bajar a 34 bytes:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Dennis
Cuando originalmente había analizado su solución, estaba un poco desconcertado de cómo ingresó -a la salida sin que aparezca en el código y sin una condición. Ahora lo entiendo: ¡viene de convertir el valor final en un número negativo! Nunca se me habría ocurrido esto, así que me sentiría mal por copiarlo. ¡Trataré de aprender de eso la próxima vez! :)
Reto Koradi
Lo suficientemente justo. ¿Qué tal l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q? S} / `aunque? Eso es mucho más similar a su propio código y pesa solo 33 bytes.
Dennis
@ Dennis Ok, si insistes. :) En realidad, tomando la idea clave de generar un valor negativo para el final del intervalo, parece una forma razonablemente sencilla de implementarlo. Gracias.
Reto Koradi
2

CoffeeScript, 178161 bytes

Al igual que mi respuesta de JavaScript. Necesito averiguar si usar las comprensiones resultará en un código más corto.

f=(n)->s=e=o='';n.split(' ').map(Number).sort((a,b)->a-b).map((v)->s=s||v;(o+=s+(if s<e then'-'+e else'')+' ';s=v)if(e&&v>e+1);e=v);o+(if s<e then s+'-'else'')+e

Original:

f=(n)->o='';s=e=0;n.split(' ').map(Number).sort((a,b)->a-b).forEach((v,i)->if!i then s=v else(o+=s+(if s<e then'-'+e else'')+' ';s=v)if(v!=e+1);e=v);o+(if s<e then s+'-'else'')+e
rink.attendant.6
fuente
1

Python 2, 126 122 121 Bytes

Sé que esto puede acortarse, simplemente no sé dónde ... Requiere entrada en forma [#, #, #, #, ..., #].

l=sorted(input());s=`l[0]`;c=0;x=1
while x<len(l):y,z=l[x],l[x-1];s+=(('-'+`z`)*c+' '+`y`)*(y-z>1);c=(y-z<2);x+=1
print s
Kade
fuente
Parece encontrar soluciones con execbastante frecuencia.
mbomb007
@ mbomb007 Puede que estés pensando en xnor :) Y creo que en esta situación, el bucle podría ser de la misma longitud, incluso más corto (aún no he jugado lo suficiente).
Kade
1
Debería poder reemplazar while x<len(l)con while l[x:]para guardar algunos bytes.
Mathmandan
1

Java, 191 bytes

void f(int[]a){java.util.Arrays.sort(a);for(int b=a.length,c=b-1,i=0,j=a[0],l=j;++i<b;){if(a[i]!=++j||i==c){System.out.print((l+1==j?l+(i==c?" "+a[c]:""):l+"-"+(i==c?j:j-1))+" ");l=j=a[i];}}}

Comprueba los rangos y los imprime en consecuencia. Desafortunadamente, tuve que hacer un caso especial para el último elemento en la matriz ya que el programa terminaría sin imprimir el último número o rango.

TNT
fuente
1

Java, 171 162 bytes

String s(int[] n){Arrays.sort(n);int p=0,b=0;String r="",d="";for(int c:n){if(c==++p)b=1;else{if(b==1){r+="-"+--p+d+c;p=c;b=0;}else{r+=d+c;p=c;}d=" ";}}return r;}

Toma la entrada como una matriz int, devuelve la salida como una lista de cadenas separadas por espacios

vijrox
fuente