Unione degli intervalli


15

Dato un elenco di intervalli, eseguirne l'unione e ridurre le sovrapposizioni. Ciò significa che le parti sovrapposte sono ridotte. ( [a, b] U [c, d] = [a, d]if b > c) Supponendo che tutto a <b in tutti gli intervalli [a, b]. Implementare in funzione di un elenco di intervalli di input -> elenco di intervalli di output. Il codice più corto vince. Non è possibile utilizzare alcuna libreria esistente.

chiarimenti:

  • Gli intervalli aperti e chiusi non si distinguono.
  • Intervalli per numeri reali, non numeri interi. ( [2, 3], [4, 5] -> [2, 3], [4, 5])
  • Non è necessario ordinare gli intervalli di output
  • L'ordine se gli input non contano
  • Gli input illegali sono solo [a, b]dove b >= a, non ha nulla a che fare con l'ordine degli intervalli di input e il numero di intervalli di input.
  • Non è necessario mostrare un messaggio di errore su comportamenti indefiniti

Esempi (con righe numeriche)

 [2, 4], [7, 9] --> [2, 4], [7, 9]
   234
        789
-> 234  789

 [1, 5], [2, 10] --> [1, 10] (overlapping [2, 5] reduced)

   12345
    234567890
-> 1234567890
 [2, 4], [3, 6], [8, 9] -> [2, 6], [8, 9]
   234
    3456
         89
-> 23456 89

 [4, 2], [2, 2] -> (undefined behavior: against the assumption)

3
Gli intervalli saranno sempre ordinati come nei tuoi esempi?
Peter Olson,

1
Perché [2, 3], [4, 5] non si sovrappongono o [2, 4], [4, 5]? Entrambi cedono 2345.
mellamokb,

2
Gli intervalli sono solo sull'insieme di numeri interi?
Lowjacker,

2
Abbiamo bisogno di alcuni chiarimenti: 1) È [4,5], [1,2] input legale? 2) L'output di [2,3], [4,5] dovrebbe essere [2,5] o [2,3], [4,5]? 3) L'output di [2,3], [3,4] dovrebbe essere [2,4] o [2,3], [3,4]?
MtnViewMark,

1
Grazie per i chiarimenti, ma "Non è necessario ordinare" significa cosa? Che l'output non deve essere ordinato? O che l'input è già ordinato?
MtnViewMark

Risposte:


2

GolfScript, 32

[{1$1$*-2%~2->{*$[(\)\;]}{}if}*]
  • Aggiungi 2 caratteri se preferisci un blocco, 4 se preferisci un blocco con nome.
  • Input e output sono array di coppie, ad es [[2 4] [3 5]]
  • Suppone che l'input sia ordinato dal primo elemento.
  • Compatta intervalli "adiacenti" ([2 4] [5 6] -> [2 6])
  • Primo sforzo GolfScript. Consigli e frutta marcia apprezzati.

Programma completo di test:

[~](;2/[{1$1$*-2%~2->{*$[(\)\;]}{}if}*]`

Esempio di invocazione:

ruby golfscript.rb intervals.gs <<EOF
3
2 4
3 6
8 9
EOF
# Expected output: [[2 6] [8 9]]

4

Haskell (103)

Penso che sia troppo prolisso per Haskell. Grazie a Hoa Long Tam per la sua funzione di smistamento.

m%(x:y)|x>m=m:x:y|2>1=x:m%y;m%_=[m]
(x:y)?l|x`elem`l=y?l|0<1=x:y?(x:l);a?_=a
a∪b=foldr(%)[](a++b)?[]

In Haskell, un intervallo da aa bè indicato da [a..b]. La mia notazione è molto simile alla notazione matematica. Usalo in questo modo:

[a..b] ∪ [c..d] ∪ ... ∪ [y..z]

3

Ok, ecco il mio crack da 250 personaggi.

void n(int a[]){if(!a[2])return;if(a[2]<=a[1]){if(a[1]<a[3])a[1]=a[3];
int *b=a+2;while(*b=*(b+2))++b;n(a);}n(a+2);}
void m(int a[]){if(!a[2])return;if(a[0]>a[2]){int s=a[0],t=a[1];
a[0]=a[2];a[2]=s;a[1]=a[3];a[3]=t;m(a+2);m(a);n(a);}m(a+2);n(a+2);}

La funzione accetta un array int e vi opera in situ. L'array è terminato da uno 0 e gli intervalli possono essere indicati in qualsiasi ordine.

Uscita campione:

input list: (7,9) (5,6) (1,4) (15,18) (13,16) (2,3) (8,11) 
output list: (1,4) (5,6) (7,11) (13,18) 

Programma di esempio:

#include <stdio.h>

void n(int a[]){if(!a[2])return;if(a[2]<=a[1]){if(a[1]<a[3])a[1]=a[3];
int *b=a+2;while(*b=*(b+2))++b;n(a);}n(a+2);}
void m(int a[]){if(!a[2])return;if(a[0]>a[2]){int s=a[0],t=a[1];
a[0]=a[2];a[2]=s;a[1]=a[3];a[3]=t;m(a+2);m(a);n(a);}m(a+2);n(a+2);}


/*
void n(int a[])
{
    if(!a[2])return;
    if(a[2]<=a[1]) {
        if(a[1]<a[3])
            a[1]=a[3];
        int *b=a+2;
        while(*b=*(b+2))++b;
        n(a);
    }
    n(a+2);
}

void m(int a[])
{
    if(!a[2])return;
    if(a[0]>a[2]) {
        int s=a[0],t=a[1];
        a[0]=a[2];a[2]=s;
        a[1]=a[3];a[3]=t;
        m(a+2);m(a);n(a);
    }
    m(a+2);n(a+2);
}
*/

void p(int a[]) 
{
    if(!*a) {
        printf("\n");
        return;
    }
    printf("(%d,%d) ",a[0],a[1]);
    p(a+2);
}

int main (int argc, const char * argv[]) 
{
    // Code golf entry
    // Interval Merging

    int a[] = {7,9,5,6,1,4,15,18,13,16,2,3,8,11,0};
    printf( "input list: " ); p(a);
    m(a);
    printf( "output list: " ); p(a);

    return 0;
}

perform the union of themdovrebbe portare a (1,11) (13,18), no?
utente sconosciuto

@utente sconosciuto: avrei pensato la stessa cosa, ma immagino che le istruzioni dicano combinano solo se si sovrappongono. Quindi (1, 4) (5, 6) non sono combinati secondo la regola ([a, b] U [c, d] = [a, d] if b > c). E del resto, anche (1, 5) (5, 6) non sarebbero combinati.
mellamokb,

"Dato un elenco di intervalli, eseguine l'unione e riduci le sovrapposizioni" andriduci le sovrapposizioni - no if they overlap. OK: i seguenti that means ...punti sono di nuovo nella direzione opposta.
utente sconosciuto

@utente sconosciuto: sono d'accordo. Ecco perché l'ho commentato sulla domanda. Spero che l'OP risponderà :)
mellamokb

2

Python, 100 caratteri

def f(L):R=sorted(set(p for p in sum(L,[])if 1-any(x<p<y for x,y in L)));return zip(R[::2],R[1::2])
print f([[2, 4], [7, 9]])
print f([[1, 5], [2, 10]])
print f([[3, 6], [2, 4], [8, 9]])
print f([[1, 5], [3, 5], [4, 5]])

genera

[(2, 4), (7, 9)]
[(1, 10)]
[(2, 6), (8, 9)]
[(1, 5)]

Prende tutti gli endpoint degli intervalli, rimuove quelli che si trovano rigorosamente all'interno di un altro intervallo, li unifica e li ordina e li accoppia.



2

Haskell, 55 caratteri

v(q@(a,b):p@(c,d):r)|c>b=q:v(p:r)|1<3=v((a,d):r);v x=x

Se l'input non è ordinato, allora 88 caratteri:

p@(a,b)§(q@(c,d):r)|b<c=p:q§r|a>d=q:p§r|1<3=(min a c,max b d)§r;p§_=[p]
u i=foldr(§)[]i

Esecuzioni di test:

ghci> testAll v
pass: [(2,4),(7,9)] --> [(2,4),(7,9)]
pass: [(1,5),(2,10)] --> [(1,10)]
pass: [(2,4),(3,6),(8,9)] --> [(2,6),(8,9)]
ghci> testAll u
pass: [(2,4),(7,9)] --> [(2,4),(7,9)]
pass: [(1,5),(2,10)] --> [(1,10)]
pass: [(2,4),(3,6),(8,9)] --> [(2,6),(8,9)]

Suppongo che "non è possibile utilizzare alcuna libreria esistente" preclude l'importazione Liste la chiamata sort. Se ciò fosse legale, la versione non ordinata sarebbe di soli 71 caratteri.


l'importazione Listdal pacchetto Haskell98sarebbe sufficiente IMHO.
FUZxxl,

2

Scala, 272 caratteri

type p=List[(Int,Int)];def f(l:p):p={var(a,s,c,o)=(new Array[Int]((l map(x=>x._2)max)+1),0,0,List[Int]());l map(x=>(a(x._1)+=1,a(x._2)-=1));while(c<a.size){s+=a(c);if(a(c)==1&&s==1)o=o:+c;if(a(c)== -1&&s==0)o=o:+c;c+=1};return(o.grouped(2).map(x=>(x.head,x.last)).toList)}

Uso:

object Intervals2 extends Application
{
    type p=List[(Int,Int)];def f(l:p):p={var(a,s,c,o)=(new Array[Int]((l map(x=>x._2)max)+1),0,0,List[Int]());l map(x=>(a(x._1)+=1,a(x._2)-=1));while(c<a.size){s+=a(c);if(a(c)==1&&s==1)o=o:+c;if(a(c)== -1&&s==0)o=o:+c;c+=1};return(o.grouped(2).map(x=>(x.head,x.last)).toList)}

    print(f(List((1,2),(3,7),(4,10))))
}

Crea un array e inserisce un 1 per ogni inizio di intervallo e un -1 per ogni fine di intervallo. Quindi passa attraverso l'array aggiungendo i valori a un contatore emettendo un inizio ogni volta che il contatore passa da 0 a 1 e termina quando passa da 1 a 0. Probabilmente complicato inutilmente.

Produzione:

List((1,2), (3,10))

1

Perl (146) (92) (90)

golf fino a 90 caratteri, usando creativamente il motore regex

sub u {mappa $ h [$ _] = 1, @ $ _ [0] .. @ $ _ [1] per @_; $ w. = $ _ + 0per @ h; push @ r, $ - [0 ], $ + [0] -1while $ w = ~ / 1 + / g; @r}

esempio di utilizzo:

my @ out1 = u ([1, 5], [2, 10]); # (1,10)
my @ out2 = u ([2, 4], [3, 6], [8, 9]); # (2, 6, 8, 9)

spieghiamo un po 'questo codice.

questa subroutine riceve un array di arrayrefs, ciascuno dei quali punta a un array contenente due elementi, inizio e fine dell'intervallo: ([2, 4], [3, 6], [8, 9])

per ogni are, generiamo una matrice di elementi dal primo all'ultimo ($_->[0] .. $_->[1]). quindi usiamo map per impostare elementi di tali indici in @h a 1.

per (@_) {
    mappa {$ h [$ _] = 1} ($ _-> [0] .. $ _-> [1]);
}

successivamente, @hconterrà uno (per intervalli) o undefs, rappresentati di seguito come trattini per maggiore chiarezza.

indice: 0 1 2 3 4 5 6 7 8 9
@h: - - 1 1 1 1 1 - 1 1

poi costruiamo una stringa da @h, aggiungendo 0 per sostituire undefs con qualcosa di più utile (undef + 0 = 0).

$w .= $_+0 for @h;

$ w contiene 011111011ora.

è tempo di abusare un po 'del motore regex.

push @r, ($-[0], $+[0]-1) while $w=~/1+/g;

dopo le partite riuscite, le matrici @ - e @ + contengono rispettivamente la posizione di inizio e fine di ciascuna partita; Il 0 ° elemento viene utilizzato per l'intera partita, prima per $ 1, seconda per $ 2 e così via.

$+[0] in realtà contiene la posizione del primo carattere non corrispondente, quindi dobbiamo sottrarre uno.

@rcontiene (2, 6, 8, 9)ora.

@r

per rendere il sub ritorno @r.


Non funziona per i [2,3],[4,5]rendimenti in numeri reali2 5
Xcali

1

Scala 305 279 caratteri senza invocazione:

type I=(Int,Int)
def l(p:I,q:I)=if(p._1<q._1)true else if(p._1>q._1)false else p._2<q._2
def r(l:List[I]):List[I]=l match{case x::y::z=>{if(y._1<=x._2&&y._2>x._2)(x._1,y._2)::r(z)else
if(y._1<=x._2&&y._2<=x._2)x::r(z)else  
x::r(y::z)}case _=>l}
def c(v:List[I])=r(v.sortWith(l))

invocazione:

val i=List((7,9),(5,6),(1,4),(15,18),(13,16),(2,3),(8,11))
c(i)
res0: List[(Int, Int)] = List((1,4), (5,6), (7,11), (13,18))

1

Brachylog , 12 byte

⟦₂ᵐcod~c~⟦₂ᵐ

Provalo online!

Una soluzione deliziosamente dichiarativa, prendendo l'input come un elenco di elenchi attraverso la variabile di input e producendo un elenco di elenchi attraverso la variabile di output.

        ~⟦₂ᵐ    The output is a list of intervals, where each interval is a range in
      ~c        the smallest partition of
  ᵐ             each element of the input
⟦₂              converted to an inclusive range,
   c            concatenated,
    o           sorted,
     d          and deduplicated
        ~⟦₂ᵐ    for which each element of the partition is a range.

1

Clojure, 138 byte

#(let[S(set(apply mapcat range(apply map list %)))Q(sort S)](map list(for[s Q :when(not(S(dec s)))]s)(for[s(map inc Q):when(not(S s))]s)))

Questo si riduce a 119 byte se l'ingresso è più flessibile, vale a dire un elenco di punti di inizio degli intervalli E un elenco di punti di fine degli intervalli:

#(let[S(set(mapcat range % %2))Q(sort S)](map list(for[s Q :when(not(S(dec s)))]s)(for[s(map inc Q):when(not(S s))]s)))

Deve esserci un modo migliore.


1

Japt , 18 byte

Sembra troppo lungo. I / O ordinati, array 2D di intervalli.

c_ròÃòÈaY Éîg[TJ]

Provalo


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.