Bestimmen Sie Bereiche aus einer Liste von Werten

18

Bei einer unsortierten Liste eindeutiger, positiver Ganzzahlen geben Sie die kürzeste Liste der längsten Bereiche sequentieller Ganzzahlen aus.

EINGANG

  • Eine unsortierte Liste eindeutiger positiver Ganzzahlen
    • z.B 9 13 3 11 8 4 10 15
  • Die Eingabe kann aus einer der folgenden Quellen erfolgen:
    • stdin
    • Kommandozeilenargumente
    • Funktionsargumente

AUSGABE

  • Eine geordnete Liste von Bereichen oder einzelnen Werten, die in einer Zeile auf stdout oder die ähnlichste Ausgabe Ihrer Sprache gedruckt sind.
    • Wenn zwei oder mehr sequentielle Ganzzahlen (sequentiell nach Wert, nicht nach Ort in der Liste) vorhanden sind, werden sie mit - als einschließender Bereich bezeichnet, z 8-11
    • Alle anderen Ganzzahlen werden einfach ohne andere Notation gedruckt
    • Ein einzelnes Leerzeichen begrenzt die Ausgabe
  • Zahlen, die nicht in der Eingabe vorhanden sind, sollten nicht in der Ausgabe enthalten sein, z. B. 3 5 6können sie nicht auf abgekürzt werden, 3-6da sie 4nicht vorhanden sind

Beispiele

Erfolgreich:

 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

Falsch:

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

Bereich enthält Werte, die nicht in der Eingabe enthalten sind

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

Alle sequentiellen Werte sollten als Bereich dargestellt werden

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

Geteilter Bereich, 8-9und 10-11sollte sein8-11

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

Ausgabe nicht korrekt bestellt

REGELN

  • Standardlücken sind nicht zulässig
  • Wenn Ihre Sprache eine Funktion hat, ist dies nicht zulässig
  • Sie können ein vollständiges Programm oder eine Funktion schreiben
  • Das nachgestellte Leerzeichen spielt keine Rolle

WERTUNG

  • Wenigste Bytes gewinnt
Corey Ogburn
quelle
1
Der erste Satz ist wirklich verwirrend. Ich würde empfehlen, "die kürzeste Liste der längsten Bereiche sequentieller Ganzzahlen ausgeben" zu sagen. Ansonsten schöne Herausforderung!
Nathan Merrill
2
Ich bin mir ziemlich sicher, dass wir diese Herausforderung schon einmal hatten, aber ich finde nicht die richtigen Suchbegriffe. Erinnert sich noch jemand?
Donnerstag,
4
@CoreyOgburn Übrigens, was hat Sie dazu veranlasst, auf PPCG zu posten? Wir versuchen herauszufinden, warum wir eine ganze Reihe neuer Benutzer haben.
xnor
2
@xnor Ich habe die Seite monatelang im Auge behalten. Keine der Sprachen, die ich verwende, ist normalerweise ein guter Kandidat für Antworten, und ich hatte bis heute keine Frage zum Posten.
Corey Ogburn
1
@xnor: Es ist ähnlich wie Maltysens Hausaufgabenliste, aber nicht identisch.
Alex A.

Antworten:

9

Python 2, 123 120 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:])

Wenn die Eingabe eine Liste als Funktionsargument sein kann, dann (danke mbomb007 und xnor für die Bedingungen)

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, wenn führende Leerzeichen akzeptabel sind - lassen Sie das Finale fallen [1:])

Ruth Franklin
quelle
Sie können zu wechseln str(n), `n`um ein paar Bytes zu sparen, wenn Sie zu Python 2 wechseln.
mbomb007
Sie können auch eine Funktion , die eine Liste als Eingabe anstelle von erstellen raw_input(), und Sie können ändern '-'+`n`zu `-n`. Und da Sie jetzt Python 2 verwenden, können Sie die Klammern nach dem entfernen print.
mbomb007
Die Saite Stück für Stück zu generieren ist clever. Zum Speichern von Bytes ist es im Allgemeinen kürzer, Bedingungen durch Listenauswahl oder Arithmetik wie def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](die weiter vertieft werden können) auszuführen.
Donnerstag,
Möglicherweise können Sie set(N)anstelle von verwenden sorted(N); Dies wird bei Verwendung von cPython korrekt von kleinstem zu kleinstem iterieren, funktioniert jedoch nicht für alle Implementierungen, sodass sich die Frage stellt, ob dies gültig ist oder nicht.
KSab
6

JavaScript (ES6): 171 154 140 137 Byte

Danke edc65 und vihan1086 für die Tipps! [...n]ist sehr schön , funktioniert aber in diesen Fällen aufgrund von mehrstelligen Zahlen nicht.

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

ES5-Variante, 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
quelle
n.split ohne runde Klammern ist mir völlig neu! Aber [...n]ist besser
edc65
@ edc65 Danke, hätte nie gedacht, den String so auszupacken.
rink.attendant.6
Schauen Sie sich dies an: codegolf.stackexchange.com/questions/37624/…
edc65 29.06.15
... aber ... funktioniert das mit einem der Beispiele? Da es mehrstellige Zahlen gibt, müssen Sie die Zeichenfolge "" (Leerzeichen) und nicht "" (leere Zeichenfolge) aufteilen. Ich habe dir wahrscheinlich den falschen Tipp gegeben
edc65 29.06.15
@ edc65 Ich dachte, etwas sieht anders aus, als mir klar wurde, dass die Testfälle fehlgeschlagen sind. Trotzdem ist es immer noch gut, etwas Neues zu lernen
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

Dies ist eine leicht golfene Version aus einem Beispiel in den Dokumenten für slice_when .

steenslag
quelle
4

CJam, 35 Bytes

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

Probieren Sie es online im CJam-Interpreter aus .

Wie es funktioniert

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
quelle
4

Ruby, 70 Bytes

Probleme wie diese veranlassen mich, die Ruby-API auf geeignete Methoden zu überprüfen. Heute habe ich eine neue entdeckt Array#slice_when:, die in Ruby v2.2 neu eingeführt wurde und anscheinend genau für diese Situation gedacht ist :)

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

Nach dem Sortieren und geeigneten Aufteilen des Arrays nimmt es jedes Unterarray, erstellt eine Zeichenfolge aus dem höchsten und dem niedrigsten Element und fügt dann das gesamte Array zu einer Zeichenfolge zusammen.

Beispiel:

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

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

Ziemlich schlecht, aber andererseits ist Prolog eine schreckliche Golfsprache

Beispiel: a([9,13,3,11,8,4,10,15,6]).Ausgänge3-4 6 8-11 13 15

Tödlich
quelle
3

CJam, 38 33 Bytes

Neue Version mit Ideen und Codefragmenten von @Dennis:

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

Probieren Sie es online aus

Das Eingabeformat ist ein CJam-Array in eckigen Klammern.

Die Grundidee hier ist, dass ich zuerst eine monotone Sequenz von der sortierten Eingabesequenz subtrahiere:

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 diesem Unterschied haben Werte, die Teil desselben Intervalls sind, denselben Wert. Durch Anwenden des CJam-RLE-Operators auf diesen Unterschied werden die Intervalle direkt aufgelistet.

Die subtrahierten sequentiellen Werte müssen während der Ausgabe zurückaddiert werden. Ich bin nicht ganz zufrieden damit, wie das in meinem Code gemacht wird. Ich vermute, ich könnte ein paar Bytes sparen, wenn ich das eleganter handhaben würde.

Zur Generierung der Ausgabe der Intervalle wird Dennis 'Idee verwendet, eine negative Zahl für den Endwert zu generieren, die sich um die Generierung von a kümmert - wird. Außerdem wird die Logik vereinfacht, da abhängig von der Intervallgröße nur ein Wert hinzugefügt / weggelassen werden muss .

Erläuterung:

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
quelle
Das ist eine clevere Verwendung von RLE! Durch Ausleihen des Bereichshandlings und des Eingabeformats aus meiner Antwort können Sie bis zu 34 Bytes erreichen:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Dennis,
Als ich mir Ihre Lösung ursprünglich angeschaut hatte, war ich ziemlich verwirrt darüber, wie Sie eine -in die Ausgabe bekommen haben, ohne dass sie im Code angezeigt wird und ohne dass eine Bedingung vorliegt. Jetzt verstehe ich es: Es kommt davon, den Endwert in eine negative Zahl umzuwandeln! Ich hätte mir das nie ausgedacht, deshalb würde ich mich schlecht fühlen, wenn ich es kopiere. Ich werde versuchen, für das nächste Mal daraus zu lernen! :)
Reto Koradi
Meinetwegen. Wie wäre es mit l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q? S} / `? Das ist Ihrem eigenen Code viel ähnlicher und wiegt nur 33 Bytes.
Dennis
@ Tennis Ok, wenn Sie darauf bestehen. :) Wenn man die Grundidee annimmt, einen negativen Wert für das Intervallende zu generieren, sieht dies nach einer recht einfachen Art der Implementierung aus. Vielen Dank.
Reto Koradi
2

CoffeeScript, 178 161 Bytes

Genau wie meine JavaScript-Antwort. Ich muss herausfinden, ob die Verwendung von Verständnis zu kürzerem Code führt.

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
quelle
1

Python 2, 126 122 121 Bytes

Ich weiß, dass dies kürzer werden kann, weiß nur nicht, wo. Erfordert Eingaben in Form [#, #, #, #, ..., #].

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
quelle
Sie scheinen mit execziemlich oft Lösungen zu finden .
mbomb007
@ mbomb007 Du denkst vielleicht an xnor :) Und ich denke in dieser Situation ist das Looping vielleicht gleich lang, sogar kürzer (habe noch nicht genug damit gespielt).
Kade
1
Sie sollten ersetzen können while x<len(l)mit while l[x:]zu speichern wenigen 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];}}}

Prüft auf Bereiche und druckt sie entsprechend aus. Leider musste ich für das letzte Element im Array einen Sonderfall machen, da das Programm beendet wurde, ohne die letzte Zahl oder den letzten Bereich auszudrucken.

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

Übernimmt die Eingabe als int-Array und gibt die Ausgabe als durch Leerzeichen getrennte String-Liste zurück

vijrox
quelle