Określ zakresy na podstawie listy wartości

18

Biorąc pod uwagę nieposortowaną listę unikatowych, dodatnich liczb całkowitych, wypisz najkrótszą listę z najdłuższych możliwych zakresów liczb całkowitych sekwencyjnych.

WEJŚCIE

  • Nieposortowana lista unikalnych, dodatnich liczb całkowitych
    • na przykład 9 13 3 11 8 4 10 15
  • Dane wejściowe można pobrać z jednego z poniższych:
    • stdin
    • argumenty wiersza poleceń
    • argumenty funkcji

WYNIK

  • Uporządkowana lista zakresów lub poszczególnych wartości drukowana w jednym wierszu na standardowe wyjście lub najbliższy podobny wynik w twoim języku.
    • Jeśli obecne są dwie lub więcej kolejnych liczb całkowitych (sekwencyjnych według wartości, a nie według lokalizacji na liście), zostaną one oznaczone jako zakres obejmujący za pomocą -, np. 8-11
    • Wszystkie inne liczby całkowite są po prostu drukowane bez żadnej innej notacji
    • Pojedyncza spacja ograniczy wynik
  • Liczby nieobecne na wejściu nie powinny znajdować się na wyjściu, np. 3 5 6Nie można ich skrócić, 3-6ponieważ 4nie jest obecny

PRZYKŁADY

Odnoszący sukcesy:

 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

Źle:

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

Zakres zawiera wartości, których nie ma na wejściu

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

Wszystkie kolejne wartości powinny być reprezentowane jako zakres

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

Podzielony zakres 8-9i 10-11powinien być8-11

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

Wyjście nie zostało poprawnie zamówione

ZASADY

  • Standardowe luki są niedozwolone
  • Jeśli Twój język ma taką funkcję, jest to niedozwolone
  • Możesz napisać pełny program lub funkcję
  • końcowe białe znaki nie mają znaczenia

PUNKTACJA

  • Najmniej bajtów wygrywa
Corey Ogburn
źródło
1
Pierwsze zdanie jest bardzo mylące. Polecam powiedzenie „wypisz najkrótszą listę najdłuższych możliwych zakresów liczb całkowitych sekwencyjnych”. W przeciwnym razie miłe wyzwanie!
Nathan Merrill
2
Jestem prawie pewien, że mieliśmy już takie wyzwanie, ale nie mam odpowiednich kryteriów wyszukiwania. Czy ktoś pamięta?
xnor
4
@CoreyOgburn Przy okazji, co skłoniło cię do opublikowania postu na PPCG? Próbujemy dowiedzieć się, dlaczego przybywa cała masa nowych użytkowników.
xnor
2
@xnor Od miesięcy mam oko na stronę. Żaden z używanych przeze mnie języków nie jest zwykle dobrym kandydatem na odpowiedź i do dziś nie miałem pytania.
Corey Ogburn,
1
@xnor: Jest podobny do pierwszej listy zadań domowych Maltysena, ale nie jest identyczny.
Alex A.

Odpowiedzi:

9

Python 2, 123 120 bajtów

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

Jeśli dane wejściowe mogą być listą jako argumentem funkcji, to (dzięki mbomb007 i xnor za instrukcje warunkowe)

93 90 81 bajtów

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

(77 bajtów, jeśli dopuszczalne są wiodące białe znaki - upuść końcowy [1:])

Ruth Franklin
źródło
Możesz zmienić, str(n)aby `n`zapisać kilka bajtów, jeśli przełączysz się na Python 2.
mbomb007
Możesz także utworzyć funkcję, która zamiast danych pobiera listę jako dane wejściowe raw_input(), i możesz zmienić '-'+`n`na `-n`. A ponieważ używasz teraz języka Python 2, możesz usunąć nawiasy po print.
mbomb007
Generowanie struny kawałek po kawałku jest sprytne. Aby zaoszczędzić bajty, generalnie krótsze jest robienie warunkowe przez wybór listy lub arytmetykę, np. def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](Które można dalej grać w golfa).
xnor
Możesz być w stanie użyć set(N)zamiast sorted(N); spowoduje to poprawną iterację od najmniejszej do najniższej przy użyciu cPython, ale nie gwarantuje się, że będzie działać dla wszystkich implementacji, więc jest pewne pytanie, czy jest to poprawne.
KSab
6

JavaScript (ES6): 171 154 140 137 bajtów

Dzięki edc65 i vihan1086 za wskazówki! [...n]jest bardzo fajny, ale nie działa w takich przypadkach ze względu na liczby wielocyfrowe.

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

Wariant ES5, 198 184 183 174 bajtów

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

lodowisko. dozorca 6
źródło
n.split bez nawiasów jest dla mnie zupełnie nowy! Ale [...n]jest lepiej
edc65
@ edc65 Dzięki, nigdy nie myślałem o rozpakowaniu takiego łańcucha.
rink.attendant. 6
... ale ... czy to działa z dowolnym przykładem? istnieją liczby wielocyfrowe, więc potrzebujesz podziału na „” (spację), a nie „” (pusty ciąg). Prawdopodobnie dałem ci złą wskazówkę
edc65,
@ edc65 Myślałem, że coś wygląda inaczej, ale zdałem sobie sprawę, że testy zakończyły się niepowodzeniem. Nadal dobrze jest nauczyć się czegoś nowego
rink.attendant. 6
4

Rubin, 86 84 bajtów

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

Jest to lekko golfowa wersja z przykładu w dokumentacji dla slice_when .

steenslag
źródło
4

CJam, 35 bajtów

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

Wypróbuj online w interpretatorze CJam .

Jak to działa

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
źródło
4

Rubinowy, 70 bajtów

Problemy takie jak te powodują, że sprawdzam API Ruby pod kątem odpowiednich metod, a dziś odkryłem nowy: Array#slice_whennowo wprowadzony w Ruby v2.2 i najwyraźniej przeznaczony do tej dokładnej sytuacji :)

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

Po posortowaniu i odpowiednim pocięciu tablicy, pobiera ona każdą pod-tablicę i tworzy ciąg z najwyższego i najniższego elementu, a następnie łączy całą tablicę w ciąg.

Przykład:

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

daniero
źródło
4

SWI-Prolog, 165 162 159 bajtów

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

Całkiem źle, ale z drugiej strony Prolog to straszny język golfa

Przykład: a([9,13,3,11,8,4,10,15,6]).wyjścia3-4 6 8-11 13 15

Fatalizować
źródło
3

CJam, 38 lat 33 bajtów

Nowa wersja, wykorzystująca pomysły i fragmenty kodu sugerowane przez @Dennis:

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

Wypróbuj online

Format wejściowy to tablica CJam w nawiasach kwadratowych.

Podstawową ideą jest to, że najpierw odejmuję sekwencję monotoniczną od posortowanej sekwencji wejściowej:

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

W tej różnicy wartości, które są częścią tego samego przedziału, mają tę samą wartość. Zastosowanie operatora RLE CJam do tej różnicy bezpośrednio wylicza interwały.

Odejmowane wartości sekwencyjne należy dodać z powrotem podczas generowania. Nie jestem do końca zadowolony z tego, jak to się dzieje w moim kodzie. Podejrzewam, że mógłbym zaoszczędzić kilka bajtów w bardziej elegancki sposób.

Do generowania danych wyjściowych przedziałów wykorzystuje pomysł Dennisa, aby wygenerować liczbę ujemną dla wartości końcowej, która zajmuje się wytworzeniem - , a także upraszcza logikę, ponieważ tylko jedna wartość musi być dodana / pominięta w zależności od wielkości przedziału .

Wyjaśnienie:

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
źródło
To sprytne zastosowanie RLE! Pożyczając obsługę zakresu i format wejściowy z mojej odpowiedzi, możesz dostać się do 34 bajtów:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Dennis
Kiedy początkowo patrzyłem na twoje rozwiązanie, byłem trochę zdziwiony, w jaki sposób dostałeś się -do wyjścia bez pokazania go w kodzie i bez warunku. Teraz rozumiem: Pochodzi z zamiany wartości końcowej na liczbę ujemną! Nigdy bym tego nie wymyślił, więc źle byłoby mi go skopiować. Spróbuję się od tego uczyć następnym razem! :)
Reto Koradi
Słusznie. Co powiesz na l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q? S} / `chociaż? Jest to o wiele bardziej podobne do twojego kodu i waży tylko 33 bajty.
Dennis
@Dennis Ok, jeśli nalegasz. :) Właściwie, biorąc pod uwagę kluczowy pomysł generowania wartości ujemnej dla końca interwału, wygląda to na dość prosty sposób na jej wdrożenie. Dzięki.
Reto Koradi
2

CoffeeScript, 178 161 bajtów

Tak jak moja odpowiedź JavaScript. Muszę dowiedzieć się, czy użycie wyrażeń spowoduje skrócenie kodu.

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

Oryginalny:

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
lodowisko. dozorca 6
źródło
1

Python 2, 126 122 121 bajtów

Wiem, że to może być krótsze, po prostu nie wiem, gdzie .. Wymaga wprowadzenia formularza [#, #, #, #, ..., #].

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
źródło
Wygląda na to, execże często znajdziesz rozwiązania .
mbomb007
@ mbomb007 Być może myślisz o xnor :) I myślę, że w tej sytuacji zapętlenie może być tej samej długości, nawet krótszej (nie bawiłem się już wystarczająco długo).
Kade
1
Powinieneś być w stanie wymienić while x<len(l)z while l[x:]zaoszczędzić kilka bajtów.
matmandan
1

Java, 191 bajtów

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

Sprawdza zakresy i odpowiednio je drukuje. Niestety musiałem zrobić specjalny przypadek dla ostatniego elementu w tablicy, ponieważ program zakończyłby się bez drukowania ostatniej liczby lub zakresu.

TNT
źródło
1

Java, 171 162 bajtów

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

Pobiera dane wejściowe jako tablicę int, zwraca dane wyjściowe jako rozdzieloną spacjami listę ciągów

vijrox
źródło