Визначте діапазони зі списку значень


18

Враховуючи несортований список унікальних, додатних цілих чисел, виведіть найкоротший список найдовших можливих діапазонів послідовних цілих чисел.

ВХОД

  • Несортований список унікальних, натуральних чисел
    • напр 9 13 3 11 8 4 10 15
  • Введення можна взяти з будь-якого з наступного:
    • stdin
    • Аргументи командного рядка
    • аргументи функції

ВИХІД

  • Впорядкований список діапазонів або окремих значень, надрукованих на одному рядку до stdout або найближчого подібного виводу вашої мови.
    • Якщо є два чи більше послідовних цілих чисел (послідовних за значенням, а не за місцем розташування у списку), вони будуть позначатися як інклюзивний діапазон, використовуючи - наприклад, 8-11
    • Усі інші цілі числа просто надруковані без жодних інших позначень
    • Один простір обмежує вихід
  • Числа, відсутні у вході, не повинні бути у висновку, наприклад, 3 5 6не можуть бути скорочені до, 3-6тому що 4немає

ПРИКЛАДИ

Успішно:

 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

Неправильно:

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

Діапазон містить значення, які не знаходяться на вході

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

Усі послідовні значення повинні бути представлені у вигляді діапазону

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

Ділений діапазон, 8-9і 10-11повинен бути8-11

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

Виведення неправильно упорядковано

ПРАВИЛА

  • Стандартні лазівки заборонені
  • Якщо ваша мова має функцію, це робити це заборонено
  • Ви можете написати повну програму або функцію
  • пробільний пробіл не має значення

СКОРІННЯ

  • Найменший байт виграє

1
Перше речення справді заплутане. Я рекомендую сказати "вивести найкоротший список найдовших можливих діапазонів послідовних цілих чисел". Інакше приємний виклик!
Натан Меррілл

2
Я майже впевнений, що раніше у нас виникали такі проблеми, але я не придумую правильних пошукових термінів. Хтось пам’ятає?
xnor

4
@CoreyOgburn До речі, що спонукало вас до публікації на PPCG? Ми намагаємось з’ясувати, чому у нас з’явилася ціла купа нових користувачів.
xnor

2
@xnor Я спостерігав за сайтом протягом місяців. Жодна з мов, які я використовую, як правило, не є добрими кандидатами на відповіді, і до сьогодні у мене ніколи не виникало запитання.
Корі Огберн

1
@xnor: Це схоже на список домашніх завдань Мальтісена, але не тотожне.
Алекс А.

Відповіді:


9

Python 2, 123 120 байт

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

Якщо вхід може бути списком як аргумент функції, то (дякую mbomb007 та xnor за умовні умови)

93 90 81 байт

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

(77 байт, якщо прийнятний пробільний простір - опустити фінал [1:])


Ви можете змінити, str(n)щоб `n`зберегти кілька байт, якщо перейти на Python 2.
mbomb007,

Ви також можете створити функцію, яка приймає список як вхідний, а не використовувати raw_input(), і ви можете змінити '-'+`n`на `-n`. А оскільки ви зараз використовуєте Python 2, ви можете видалити дужки після print.
mbomb007

Створення струнних шматочків за штукою є розумним. Для економії байтів, як правило, коротше робити умовні умови за вибором списку чи арифметикою (наприклад, def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](яку можна подати в гольф)).
xnor

Ви можете використовувати set(N)замість цього sorted(N); це буде правильно повторювати від найменшого до найнижчого при використанні cPython, але не гарантується, що він працює для всіх реалізацій, тому виникає питання про те, чи дійсно це чи ні.
KSab

6

JavaScript (ES6): 171 154 140 137 байт

Дякую edc65 та vihan1086 за поради! [...n]це дуже приємно, але це не працює в цих випадках через багатоцифрове число.

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, 198 184 183 174 байт

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


n.split без дужок абсолютно новий для мене! Але [...n]краще
edc65

@ edc65 Спасибі, ніколи не думав розпакувати такий рядок.
rink.attendant.6

Подивіться на цей codegolf.stackexchange.com/questions/37624/…
edc65

... але ... чи це працює з будь-яким із прикладів? є багатозначні числа, тому вам потрібен розділ на "" (порожній пробіл) не "" (порожній рядок). Я, мабуть, дав тобі неправильну пораду
edc65

@ edc65 Я думав, що щось виглядало інакше, тоді я зрозумів, що тестові випадки не вдалися. Але все-таки добре дізнатися щось нове
rink.attendant.6

4

Рубі, 86 84 байт

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

Це злегка гольф-версія з прикладу в документах для slice_when .


4

CJam, 35 байт

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

Спробуйте його в Інтернеті в інтерпретаторі CJam .

Як це працює

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.

4

Рубін, 70 байт

Такі проблеми, як правило, змушують мене перевірити API Ruby на відповідні методи, і сьогодні я відкрив новий: Array#slice_when щойно представлений у Ruby v2.2 і, здавалося б, призначений саме для цієї ситуації :)

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

Після сортування та відповідного розрізання масиву він займає кожен підмасив і створює рядок з найвищого і нижнього елемента, а потім приєднує весь цей масив до рядка.

Приклад:

f.call [9,13,3,11,8,4,10,15,6] відбитки 3-4 6 8-11 13 15


4

SWI-Prolog, 165 162 159 байт

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

Досить погано, але знову ж таки Пролог - це жахлива мова для гольфу

Приклад: a([9,13,3,11,8,4,10,15,6]).виходи3-4 6 8-11 13 15


3

CJam, 38 33 байт

Нова версія з використанням ідей та фрагментів коду, запропонованих @Dennis:

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

Спробуйте в Інтернеті

Формат введення - це масив CJam у квадратних дужках.

Основна ідея тут полягає в тому, що я віднімаю монотонну послідовність спочатку від упорядкованої вхідної послідовності:

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

У цій різниці значення, що входять до одного інтервалу, мають однакове значення. Застосування оператора CJam RLE до цієї різниці безпосередньо перераховує інтервали.

Віднімані послідовні значення потрібно додавати під час виведення. Я не зовсім задоволений тим, як це робиться в моєму коді. Я підозрюю, що я міг би зберегти кілька байт з більш елегантним способом передачі цього.

Для генерації виходу інтервалів використовується ідея Денніса про генерування від'ємного числа для кінцевого значення, яке бере участь у формуванні а -, а також спрощує логіку, оскільки потрібно додавати / опускати лише одне значення залежно від розміру інтервалу. .

Пояснення:

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.

Це розумне використання RLE! Зайнявши обробку діапазону та формат введення з моєї відповіді, ви можете опуститися до 34 байтів:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Денніс

Коли я спочатку дивився на ваше рішення, я був настільки загадований тим, як ви потрапили -у вихід, не відображаючись у коді та без умови. Тепер я розумію: це відбувається від перетворення кінцевого значення на від’ємне число! Я ніколи б не придумав цього, тому мені буде погано копіювати це. Я спробую вчитися на цьому наступного разу! :)
Рето Коради

Справедливо. Як щодо l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q? S} / `Хоча? Це набагато більше схожий на ваш власний код і важить лише 33 байти.
Денніс,

@Dennis Добре, якщо ви наполягаєте. :) Насправді, беручи до уваги ключову ідею створення негативного значення для кінця інтервалу, це виглядає як досить простий спосіб його реалізації. Спасибі.
Рето Коради

2

CoffeeScript, 178 161 байт

Так само, як моя відповідь на JavaScript. Мені потрібно зрозуміти, чи використання розумінь призведе до скорочення коду.

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

Оригінал:

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

1

Пітон 2, 126 122 121 байт

Я знаю, що це може скоротитися, просто не знаю куди. Потрібно ввести форму [#, #, #, #, ..., #].

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

Здається, ви знайдете рішення execдосить часто.
mbomb007

@ mbomb007 Можливо, ти думаєш про xnor :) І я думаю, що в цій ситуації петля може бути однакової довжини, навіть коротшою (ще не розібралися з цим достатньо).
Кейд

1
Ви повинні бути в змозі замінити while x<len(l)з , while l[x:]щоб заощадити кілька байт.
mathmandan

1

Java, 191 байт

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

Перевіряє діапазони та друкує їх відповідно. На жаль, мені довелося зробити спеціальний випадок для останнього елемента в масиві, оскільки програма завершиться без друку останнього числа або діапазону.


1

Java, 171 162 байт

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

Приймає вхід як int масив, повертає вихід у вигляді розділеного пробілом списку рядків

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.