Union d'intervalles

15

À partir d'une liste d'intervalles, effectuez l'union de ceux-ci et réduisez les chevauchements. Cela signifie que les parties qui se chevauchent sont réduites. ( [a, b] U [c, d] = [a, d]si b > c) En supposant tout a <b dans tous les intervalles [a, b]. Implémenter en fonction d'une liste d'intervalles d'entrée -> liste d'intervalles de sortie. Le code le plus court gagne. Vous ne pouvez utiliser aucune bibliothèque existante.

Clarifications:

  • Les intervalles ouverts et fermés ne sont pas distingués.
  • Intervalles pour des nombres réels, pas des entiers. ( [2, 3], [4, 5] -> [2, 3], [4, 5])
  • Pas besoin de trier les intervalles de sortie
  • L'ordre si les entrées n'ont pas d'importance
  • Les entrées illégales ne sont [a, b]là que b >= a, cela n'a rien à voir avec l'ordre des intervalles d'entrée et le nombre d'intervalles d'entrée.
  • Vous n'avez pas besoin d'afficher un message d'erreur sur les comportements non définis

Exemples (avec des lignes numériques)

 [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)
Ming-Tang
la source
3
Les intervalles seront-ils toujours triés comme dans vos exemples?
Peter Olson
1
Pourquoi [2, 3], [4, 5] ne se chevauchent-ils pas ou [2, 4], [4, 5] non plus? Ils ont tous les deux donné 2345.
mellamokb
2
Les intervalles sont-ils uniquement sur l'ensemble des entiers?
Lowjacker
2
Nous avons besoin de quelques éclaircissements: 1) Est-ce que [4,5], [1,2] apport légal? 2) La sortie de [2,3], [4,5] doit-elle être [2,5] ou [2,3], [4,5]? 3) La sortie de [2,3], [3,4] doit-elle être [2,4] ou [2,3], [3,4]?
MtnViewMark
1
Merci pour les clarifications, mais "Pas besoin de trier" signifie quoi? Que la sortie n'a pas besoin d'être triée? Ou que l'entrée est déjà triée?
MtnViewMark

Réponses:

2

GolfScript, 32

[{1$1$*-2%~2->{*$[(\)\;]}{}if}*]
  • Ajoutez 2 caractères si vous préférez un bloc, 4 si vous préférez un bloc nommé.
  • L'entrée et la sortie sont un tableau de paires, par exemple [[2 4] [3 5]]
  • Suppose que l'entrée est ordonnée par le premier élément.
  • Compacte les plages "adjacentes" ([2 4] [5 6] -> [2 6])
  • Premier effort GolfScript. Conseils & fruits pourris appréciés.

Programme de test complet:

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

Exemple d'appel:

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

Haskell (103)

Je pense que c'est beaucoup trop verbeux pour Haskell. Merci à Hoa Long Tam pour sa fonction de tri.

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)?[]

Dans Haskell, un intervalle de aà best désigné par [a..b]. Ma notation est très similaire à la notation mathématique. Utilisez-le comme ceci:

[a..b] ∪ [c..d] ∪ ... ∪ [y..z]
FUZxxl
la source
3

Ok, voici mon crack de 250 caractères.

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 fonction prend un tableau int et opère sur celui-ci in situ. Le tableau se termine par un 0 et les intervalles peuvent être donnés dans n'importe quel ordre.

Exemple de sortie:

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) 

Exemple de programme:

#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;
}
Jonathan Watmough
la source
perform the union of themdevrait conduire à (1,11) (13,18), non?
utilisateur inconnu
@user unknown: j'aurais pensé la même chose, mais je suppose que les instructions disent de ne se combiner que si elles se chevauchent. Donc (1, 4) (5, 6) ne sont pas combinés selon la règle ([a, b] U [c, d] = [a, d] if b > c). Et d'ailleurs, même (1, 5) (5, 6) ne serait pas combiné.
mellamokb
"Étant donné une liste d'intervalles, effectuez l'union de ceux-ci et réduisez les chevauchements" andréduisez les chevauchements - pas if they overlap. OK - les that means ...points suivants à nouveau dans la direction opposée.
utilisateur inconnu
@utilisateur inconnu: je suis d'accord. C'est pourquoi je l'ai commenté sur la question. J'espère que le PO répondra :)
mellamokb
2

Python, 100 caractères

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

génère

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

Prend tous les points de terminaison des intervalles, supprime ceux qui se trouvent strictement dans un autre intervalle, les unifie et les trie, et les associe.

Keith Randall
la source
98 octets
movatica
2

Haskell, 55 personnages

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

Si l'entrée n'est pas triée, alors 88 caractères:

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

Essais:

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

Je suppose que "ne peut utiliser aucune bibliothèque existante" empêche l'importation Listet l'appel sort. Si c'était légal, la version non triée ne compterait que 71 caractères.

MtnViewMark
la source
l'importation à Listpartir du paquet Haskell98serait suffisante à mon humble avis.
FUZxxl
2

Scala, 272 caractères

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

Usage:

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

Crée un tableau et insère un 1 pour chaque début d'intervalle et un -1 pour chaque fin d'intervalle. Parcourt ensuite le tableau en ajoutant les valeurs à un compteur produisant un début chaque fois que le compteur passe de 0 à 1 et une fin lorsqu'il passe de 1 à 0. Probablement inutilement compliqué.

Production:

List((1,2), (3,10))
Gareth
la source
1

Perl (146) (92) (90)

joué à 90 caractères, en utilisant de manière créative le moteur regex

sub u {map $ h [$ _] = 1, @ $ _ [0] .. @ $ _ [1] for @_; $ w. = $ _ + 0for @ h; push @ r, $ - [0 ], $ + [0] -1 tandis que $ w = ~ / 1 + / g; @r}

exemple d'utilisation:

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

expliquons un peu ce code.

ce sous-programme reçoit un tableau de références de tableau, chacun pointant vers un tableau contenant deux éléments, début et fin de l'intervalle: ([2, 4], [3, 6], [8, 9])

pour chaque aref, nous générons un tableau d'éléments du premier au dernier ($_->[0] .. $_->[1]). nous utilisons ensuite map pour définir les éléments de ces index dans @h à 1.

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

après cela, @hcontiendra soit ceux (pour les intervalles) ou undefs, représentés ci-dessous comme des tirets pour plus de clarté.

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

ensuite, nous construisons une chaîne à partir de @h, en ajoutant 0 pour remplacer undefs par quelque chose de plus utile (undef + 0 = 0).

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

$ w contient 011111011maintenant.

il est temps d'abuser un peu du moteur d'expression régulière.

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

après des correspondances réussies, les tableaux @ - et @ + contiennent respectivement la position de début et de fin de chaque correspondance; Le 0ème élément est utilisé pour la correspondance entière, d'abord pour $ 1, deuxième pour $ 2 et ainsi de suite.

$+[0] contient en fait la position du premier caractère non correspondant, nous devons donc en soustraire un.

@rcontient (2, 6, 8, 9)maintenant.

@r

pour faire le sous-retour @r.

perl chinois goth
la source
Ne fonctionne pas pour les [2,3],[4,5]rendements réels2 5
Xcali
1

Scala 305 279 caractères sans invocation:

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

invocation:

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))
Utilisateur inconnu
la source
1

Brachylog , 12 octets

⟦₂ᵐcod~c~⟦₂ᵐ

Essayez-le en ligne!

Une solution délicieusement déclarative, prenant l'entrée comme une liste de listes via la variable d'entrée et sortant une liste de listes via la variable de sortie.

        ~⟦₂ᵐ    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.
Chaîne indépendante
la source
1

Clojure, 138 octets

#(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)))

Cela raccourcit à 119 octets si l'entrée est plus flexible, à savoir une liste de points de départ d'intervalles ET une liste de points de fin d'intervalles:

#(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)))

Il doit y avoir une meilleure façon.

NikoNyrh
la source
1

Japt , 18 octets

Cela semble beaucoup trop long. E / S triées, tableau d'intervalles 2D.

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

Essayez-le

Hirsute
la source
0

Perl 5 -MList::Util=max -n , 89 octets

@r=/\S+/g;map{/ /;$`<=$r[1]?$r[1]=max@r,$'*1:(say"@r")|(@r=($`,$'))}sort{$a-$b}<>;say"@r"

Essayez-le en ligne!

Xcali
la source