Déterminer des plages à partir d'une liste de valeurs

18

Étant donné une liste non triée d'entiers positifs uniques, affichez la liste la plus courte des plages d'entiers séquentiels les plus longues possibles.

CONTRIBUTION

  • Une liste non triée d'entiers positifs uniques
    • par exemple 9 13 3 11 8 4 10 15
  • L'entrée peut provenir de l'un des éléments suivants:
    • stdin
    • arguments de ligne de commande
    • arguments de fonction

PRODUCTION

  • Une liste ordonnée de plages ou de valeurs individuelles imprimées sur une ligne vers la sortie standard ou la sortie similaire la plus proche de votre langue.
    • Si deux ou plusieurs entiers séquentiels (séquentiels par valeur, et non par emplacement dans la liste) sont présents, ils seront désignés comme une plage inclusive en utilisant -, par exemple 8-11
    • Tous les autres entiers sont simplement imprimés sans autre notation
    • Un seul espace délimitera la sortie
  • Les nombres non présents dans l'entrée ne doivent pas être dans la sortie, par exemple 3 5 6ne peuvent pas être raccourcis 3-6car 4absents

EXEMPLES

Réussi:

 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

Faux:

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

La plage contient des valeurs absentes de l'entrée

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

Toutes les valeurs séquentielles doivent être représentées par une plage

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

Plage divisée, 8-9et 10-11doit être8-11

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

Sortie non ordonnée correctement

RÈGLES

  • Les failles standard sont interdites
  • Si votre langue a une fonction pour ce faire, ce n'est pas autorisé
  • Vous pouvez écrire un programme complet ou une fonction
  • l'espace blanc arrière n'a pas d'importance

NOTATION

  • Le moins d'octets gagne
Corey Ogburn
la source
1
La première phrase est vraiment déroutante. Je recommanderais de dire "afficher la liste la plus courte des plages d'entiers séquentiels les plus longues possibles". Sinon, beau défi!
Nathan Merrill
2
Je suis sûr que nous avons déjà eu ce défi, mais je ne trouve pas les bons termes de recherche. Quelqu'un s'en souvient?
xnor
4
@CoreyOgburn Au fait, qu'est-ce qui vous a poussé à publier sur PPCG? Nous essayons de comprendre pourquoi nous avons obtenu tout un tas de nouveaux utilisateurs.
xnor
2
@xnor Je surveille le site depuis des mois. Aucune des langues que j'utilise n'est généralement un bon candidat pour les réponses et je n'ai jamais eu de question à poser avant aujourd'hui.
Corey Ogburn
1
@xnor: Il est similaire à la liste des devoirs de Maltysen, mais pas identique.
Alex A.

Réponses:

9

Python 2, 123 120 octets

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 l'entrée peut être une liste comme argument de fonction, alors (merci mbomb007 et xnor pour les conditions)

93 90 81 octets

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

(77 octets si le premier espace est acceptable - supprimez la finale [1:])

Ruth Franklin
la source
Vous pouvez changer str(n)pour `n`économiser quelques octets, si vous passez à Python 2.
mbomb007
Vous pouvez également créer une fonction qui prend une liste en entrée au lieu de l'utiliser raw_input(), et vous pouvez passer '-'+`n`à `-n`. Et puisque vous utilisez maintenant Python 2, vous pouvez supprimer les parenthèses après le print.
mbomb007
Générer la chaîne pièce par pièce est astucieux. Pour économiser des octets, il est généralement plus court de faire des conditions par sélection de liste ou par arithmétique, comme def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](qui peut être joué plus loin).
xnor
Vous pourriez être en mesure d'utiliser set(N)au lieu de sorted(N); cela itérera correctement du plus petit au plus bas lors de l'utilisation de cPython, mais il n'est pas garanti qu'il fonctionne pour toutes les implémentations.
KSab
6

JavaScript (ES6): 171 154 140 137 octets

Merci edc65 et vihan1086 pour les conseils! [...n]est très agréable mais cela ne fonctionne pas dans ces cas en raison des nombres à plusieurs chiffres.

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 octets

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
la source
n.split sans parenthèses est totalement nouveau pour moi! Mais [...n]c'est mieux
edc65
@ edc65 Merci, jamais pensé à déballer la chaîne comme ça.
rink.attendant.6
... mais ... cela fonctionne-t-il avec l'un des exemples? il y a des nombres à plusieurs chiffres, vous avez donc besoin d'un fractionnement sur un "" (espace vide) et non "" (chaîne vide). Je vous ai probablement donné le mauvais conseil
edc65
@ edc65 Je pensais que quelque chose avait l'air différent, puis j'ai réalisé que les cas de test avaient échoué. C'est quand même bon d'apprendre quelque chose de nouveau
rink.attendant.6
4

Rubis, 86 84 octets

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

Il s'agit d'une version légèrement golfée d'un exemple dans la documentation de slice_when .

steenslag
la source
4

CJam, 35 octets

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

Essayez-le en ligne dans l' interpréteur CJam .

Comment ça fonctionne

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
la source
4

Ruby, 70 octets

Des problèmes comme ceux-ci ont tendance à me faire vérifier l'API Ruby pour les méthodes appropriées, et aujourd'hui j'en ai découvert une nouvelle: Array#slice_whennouvellement introduite dans Ruby v2.2 et apparemment destinée à cette situation exacte :)

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

Après avoir trié et découpé le tableau de manière appropriée, il prend chaque sous-tableau et crée une chaîne à partir de l'élément le plus élevé et le plus bas, puis joint l'ensemble de ce tableau en une chaîne.

Exemple:

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

daniero
la source
4

SWI-Prolog, 165 162 159 octets

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

Assez mauvais mais encore une fois Prolog est une langue de golf terrible

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

Fatalize
la source
3

CJam, 38 33 octets

Nouvelle version, utilisant des idées et des fragments de code suggérés par @Dennis:

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

Essayez-le en ligne

Le format d'entrée est un tableau CJam entre crochets.

L'idée de base ici est que je soustrais d'abord une séquence monotone de la séquence d'entrée triée:

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

Dans cette différence, les valeurs qui font partie du même intervalle ont la même valeur. L'application de l'opérateur CJam RLE à cette différence énumère directement les intervalles.

Les valeurs séquentielles soustraites doivent être rajoutées lors de la sortie. Je ne suis pas entièrement satisfait de la façon dont cela se fait dans mon code. Je soupçonne que je pourrais économiser quelques octets avec une manière plus élégante de gérer cela.

Pour générer la sortie des intervalles, cela utilise l'idée de Dennis de générer un nombre négatif pour la valeur finale, qui prend soin de produire un -, et simplifie également la logique car une seule valeur doit être ajoutée / omise en fonction de la taille de l'intervalle .

Explication:

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
la source
C'est une utilisation intelligente de RLE! En empruntant la gestion des plages et le format d'entrée à ma réponse, vous pouvez descendre à 34 octets:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Dennis
Quand j'avais à l'origine examiné votre solution, j'étais un peu mystifié de voir comment vous avez entré un -dans la sortie sans qu'il apparaisse dans le code, et sans condition. Maintenant je comprends: cela vient de la transformation de la valeur finale en nombre négatif! Je ne serais jamais venu avec ça, donc je me sentirais mal de le copier. J'essaierai d'en tirer des leçons pour la prochaine fois! :)
Reto Koradi
C'est suffisant. Que diriez-vous de l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q? S} / `cependant? Cela ressemble beaucoup plus à votre propre code et ne pèse que 33 octets.
Dennis
@Dennis Ok, si vous insistez. :) En fait, prenant l'idée clé de générer une valeur négative pour la fin de l'intervalle, cela ressemble à un moyen raisonnablement simple de le mettre en œuvre. Merci.
Reto Koradi
2

CoffeeScript, 178 161 octets

Tout comme ma réponse JavaScript. J'ai besoin de comprendre si l'utilisation de compréhensions se traduira par un code plus court.

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
la source
1

Python 2, 126 122 121 121 octets

Je sais que cela peut devenir plus court, je ne sais pas où .. Nécessite une entrée sous forme [#, #, #, #, ..., #].

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
la source
Vous semblez trouver des solutions execassez souvent.
mbomb007
@ mbomb007 Vous pensez peut-être à xnor :) Et je pense que dans cette situation, le bouclage pourrait être de la même longueur, encore plus court (je n'ai pas encore assez joué avec).
Kade
1
Vous devriez pouvoir le remplacer while x<len(l)par while l[x:]pour économiser quelques octets.
mathmandan
1

Java, 191 octets

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

Vérifie les plages et les imprime en conséquence. Malheureusement, j'ai dû faire un cas spécial pour le dernier élément du tableau car le programme se terminerait sans imprimer le dernier numéro ou la dernière plage.

TNT
la source
1

Java, 171 162 octets

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

Prend l'entrée sous forme de tableau int, renvoie la sortie sous forme de liste de chaînes séparées par des espaces

vijrox
la source