Определить диапазоны из списка значений


18

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

ВХОД

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

ВЫХОД

  • Упорядоченный список диапазонов или отдельных значений напечатан в одну строку на стандартный вывод или ближайший аналогичный вывод вашего языка.
    • Если присутствуют два или более последовательных целых числа (последовательно по значению, а не по местоположению в списке), они будут обозначаться как включающий диапазон с использованием -, например, 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

Выход не упорядочен правильно

ПРАВИЛА

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

SCORING

  • Наименьшее количество байтов выигрывает

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 байт

Подобные проблемы, как правило, заставляют меня проверять Ruby API на наличие подходящих методов, и сегодня я обнаружил новый: 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-Пролог, 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

В этой разнице значения, которые являются частью одного и того же интервала, имеют одинаковое значение. Применение оператора RJ CJam к этой разности напрямую перечисляет интервалы.

Вычтенные последовательные значения должны быть добавлены обратно во время вывода. Я не совсем доволен тем, как это делается в моем коде. Я подозреваю, что мог бы сэкономить несколько байтов с более элегантным способом передачи этого.

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

Объяснение:

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 байта.
Деннис,

@ Денис Хорошо, если ты настаиваешь. :) На самом деле, принимая ключевую идею генерации отрицательного значения для конца интервала, это выглядит как достаточно простой способ его реализации. Благодарю.
Рето Коради

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

Python 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:]чтобы сохранить несколько байтов.
Матмандан

1

Ява, 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.