Determina gli intervalli da un elenco di valori


18

Dato un elenco non ordinato di numeri interi unici e positivi, genera l'elenco più breve degli intervalli più lunghi possibili di numeri interi sequenziali.

INGRESSO

  • Un elenco non ordinato di numeri interi unici e positivi
    • per esempio 9 13 3 11 8 4 10 15
  • L'input può essere preso da uno dei seguenti:
    • stdin
    • argomenti della riga di comando
    • argomenti di funzione

PRODUZIONE

  • Un elenco ordinato di intervalli o singoli valori stampati su una riga su stdout o sull'output simile più vicino alla tua lingua.
    • Se sono presenti due o più numeri interi sequenziali (sequenziali per valore, non per posizione nell'elenco), saranno indicati come un intervallo inclusivo usando -, ad es. 8-11
    • Tutti gli altri numeri interi vengono semplicemente stampati senza altra notazione
    • Un singolo spazio delimiterà l'output
  • I numeri non presenti nell'input non dovrebbero essere nell'output, ad es. 3 5 6Non possono essere abbreviati 3-6perché 4non presenti

ESEMPI

Riuscito:

 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

Sbagliato:

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

L'intervallo contiene valori non presenti nell'input

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

Tutti i valori sequenziali devono essere rappresentati come un intervallo

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

Diviso intervallo, 8-9e 10-11dovrebbe essere8-11

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

Uscita non ordinata correttamente

REGOLE

  • Le scappatoie standard non sono ammesse
  • Se la tua lingua ha una funzione per farlo, non è permesso
  • È possibile scrivere un programma completo o una funzione
  • gli spazi bianchi finali non contano

PUNTEGGIO

  • Vince il minimo byte

1
La prima frase è davvero confusa. Consiglierei di dire "output l'elenco più breve degli intervalli più lunghi possibili di numeri interi sequenziali". Altrimenti, bella sfida!
Nathan Merrill,

2
Sono abbastanza sicuro che abbiamo già avuto questa sfida prima, ma non sto arrivando con i giusti termini di ricerca. Qualcuno ricorda?
xnor

4
@CoreyOgburn A proposito, cosa ti ha spinto a pubblicare su PPCG? Stiamo cercando di capire perché abbiamo ricevuto un sacco di nuovi utenti.
xnor

2
@xnor Ho tenuto d'occhio il sito per mesi. Nessuna delle lingue che utilizzo sono in genere buoni candidati per le risposte e non ho mai avuto domande da porre fino ad oggi.
Corey Ogburn,

1
@xnor: è simile all'elenco dei compiti di Maltysen, ma non identico.
Alex A.

Risposte:


9

Python 2, 123 120 byte

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:])

Se l'input può essere un elenco come argomento di funzione, allora (grazie a mbomb007 e xnor per i condizionali)

93 90 81 byte

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

(77 byte se lo spazio bianco iniziale è accettabile - elimina il finale [1:])


Puoi passare str(n)a `n`per salvare qualche byte, se passi a Python 2.
mbomb007

È inoltre possibile creare una funzione che accetta un elenco come input anziché utilizzarlo raw_input()e si può cambiare '-'+`n`in `-n`. E poiché ora stai usando Python 2, puoi rimuovere le parentesi dopo il print.
mbomb007,

Generare la corda pezzo per pezzo è intelligente. Per il salvataggio dei byte, è generalmente più breve fare condizionali per selezione dell'elenco o aritmetica, come def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](che può essere ulteriormente golfato).
xnor

Potresti essere in grado di utilizzare set(N)invece di sorted(N); questo itererà correttamente dal più piccolo al più basso quando si usa cPython ma non è garantito che funzioni per tutte le implementazioni, quindi c'è qualche dubbio sul fatto che questo sia valido o meno.
KSab il

6

JavaScript (ES6): 171 154 140 137 byte

Grazie edc65 e vihan1086 per i suggerimenti! [...n]è molto bello ma in questi casi non funziona a causa di numeri a più cifre.

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)}

Variante ES5, 198 184 183 174 byte

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)}


n.split senza parentesi è totalmente nuovo per me! Ma [...n]è meglio
edc65,

@ edc65 Grazie, non avrei mai pensato di decomprimere la stringa in quel modo.
rink.attendant.6


... ma ... funziona con qualcuno degli esempi? ci sono numeri a più cifre, quindi è necessario uno split su "" (spazio vuoto) non "" (stringa vuota). Probabilmente ti ho dato il suggerimento sbagliato
edc65,

@ edc65 Ho pensato che qualcosa sembrava diverso, poi ho capito che i casi di test fallivano. Comunque buono per imparare qualcosa di nuovo
rink.attendant.6

4

Rubino, 86 84 byte

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

Questa è una versione leggermente giocata da un esempio nei documenti per slice_when .


4

CJam, 35 byte

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

Provalo online nell'interprete CJam .

Come funziona

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.

4

Rubino, 70 byte

Problemi come questi tendono a farmi controllare l'API Ruby per metodi adeguati, e oggi ne ho scoperto uno nuovo Array#slice_when:, appena introdotto in Ruby v2.2 e apparentemente destinato a questa situazione esatta :)

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

Dopo aver ordinato e suddiviso opportunamente l'array, prende ciascun array secondario e crea una stringa dall'elemento più alto e più basso, quindi unisce l'intero array in una stringa.

Esempio:

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


4

SWI-Prolog, 165 162 159 byte

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]).

Abbastanza male, ma poi Prolog è un linguaggio da golf terribile

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


3

CJam, 38 33 byte

Nuova versione, usando idee e frammenti di codice suggeriti da @Dennis:

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

Provalo online

Il formato di input è un array CJam tra parentesi quadre.

L'idea di base qui è che sottraggo prima una sequenza monotonica dalla sequenza di input ordinata:

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

In questa differenza, i valori che fanno parte dello stesso intervallo hanno lo stesso valore. L'applicazione dell'operatore CJam RLE a questa differenza enumera direttamente gli intervalli.

I valori sequenziali sottratti devono essere aggiunti nuovamente durante l'output. Non sono del tutto contento di come è stato fatto nel mio codice. Ho il sospetto che avrei potuto salvare qualche byte con un modo più elegante di gestirlo.

Per generare l'output degli intervalli, utilizza l'idea di Dennis di generare un numero negativo per il valore finale, che si occupa di produrre un - , e semplifica anche la logica perché è necessario aggiungere / omettere un solo valore in base alla dimensione dell'intervallo .

Spiegazione:

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.

È un uso intelligente di RLE! Prendendo in prestito la gestione dell'intervallo e il formato di input dalla mia risposta, puoi ottenere fino a 34 byte:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Dennis

Quando inizialmente avevo esaminato la tua soluzione, ero un po 'sconcertato dal modo in cui hai ottenuto un -output senza che fosse mostrato nel codice e senza una condizione. Ora capisco: deriva dalla trasformazione del valore finale in un numero negativo! Non avrei mai pensato a questo, quindi mi sentirei male a copiarlo. Proverò ad imparare da esso per la prossima volta! :)
Reto Koradi,

Giusto. Che ne dici di l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q? S} / `però? È molto più simile al tuo codice e pesa solo 33 byte.
Dennis

@Dennis Ok, se insisti. :) In realtà, prendendo l'idea chiave di generare un valore negativo per la fine dell'intervallo, questo sembra un modo ragionevolmente semplice per implementarlo. Grazie.
Reto Koradi,

2

CoffeeScript, 178 161 byte

Proprio come la mia risposta JavaScript. Devo capire se l'uso della comprensione comporterà un codice più breve.

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

Originale:

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

1

Python 2, 126 122 121 byte

So che questo può essere più breve, ma non so dove .. Richiede un input nel modulo [#, #, #, #, ..., #].

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

Sembra che tu trovi soluzioni execabbastanza spesso.
mbomb007,

@ mbomb007 Potresti pensare a xnor :) E penso che in questa situazione il loop potrebbe avere la stessa lunghezza, anche più breve (non ci ho ancora giocato abbastanza).
Kade,

1
Dovresti essere in grado di sostituire while x<len(l)con while l[x:]per salvare qualche byte.
Mathmandan,

1

Java, 191 byte

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];}}}

Verifica le gamme e le stampa di conseguenza. Sfortunatamente ho dovuto creare un caso speciale per l'ultimo elemento dell'array poiché il programma sarebbe terminato senza stampare l'ultimo numero o intervallo.


1

Java, 171 162 byte

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;}

Prende l'input come un array int, restituisce l'output come un elenco String separato da spazi

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.