Determinar intervalos de uma lista de valores


18

Dada uma lista não classificada de números inteiros positivos únicos, produza a lista mais curta dos intervalos mais longos possíveis de números inteiros seqüenciais.

ENTRADA

  • Uma lista não classificada de números inteiros positivos únicos
    • por exemplo 9 13 3 11 8 4 10 15
  • A entrada pode ser obtida de qualquer um dos seguintes:
    • stdin
    • argumentos da linha de comando
    • argumentos de função

RESULTADO

  • Uma lista ordenada de intervalos ou valores individuais impressos em uma linha para stdout ou a saída semelhante mais próxima do seu idioma.
    • Se dois ou mais números inteiros sequenciais (sequenciais por valor, não por localização na lista) estiverem presentes, eles serão indicados como um intervalo inclusivo usando -, por exemplo, 8-11
    • Todos os outros números inteiros são simplesmente impressos sem outra notação
    • Um único espaço delimitará a saída
  • Os números que não estão presentes na entrada não devem estar na saída, por exemplo, 3 5 6não podem ser encurtados 3-6porque 4não estão presentes

EXEMPLOS

Bem sucedido:

 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

Errado:

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

O intervalo contém valores que não estão na entrada

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

Todos os valores sequenciais devem ser representados como um intervalo

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

Alcance dividido 8-9e 10-11deve ser8-11

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

Saída não solicitada corretamente

REGRAS

  • As brechas padrão não são permitidas
  • Se seu idioma tem uma função para fazer isso, não é permitido
  • Você pode escrever um programa completo ou uma função
  • espaço em branco à direita não importa

PONTUAÇÃO

  • Menos bytes ganhos

1
A primeira frase é realmente confusa. Eu recomendo dizer "produza a lista mais curta dos intervalos mais longos possíveis de números inteiros seqüenciais". Caso contrário, bom desafio!
Nathan Merrill

2
Tenho certeza de que já enfrentamos esse desafio antes, mas não estou apresentando os termos de pesquisa corretos. Alguém se lembra?
xnor

4
@CoreyOgburn A propósito, o que levou você a publicar no PPCG? Estamos tentando descobrir por que temos um grupo inteiro de novos usuários entrando.
xnor

2
@xnor Eu fico de olho no site há meses. Normalmente, nenhum dos idiomas que uso são bons candidatos a respostas e nunca tive uma pergunta a postar até hoje.
Corey Ogburn

1
@xnor: É semelhante à lista de trabalhos de casa de Maltysen, mas não é idêntica.
Alex A.

Respostas:


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

Se a entrada puder ser uma lista como argumento de função, então (obrigado mbomb007 e xnor pelos condicionais)

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 se o espaço em branco inicial for aceitável - solte o final [1:])


Você pode mudar str(n)para `n`economizar alguns bytes, se você mudar para Python 2.
mbomb007

Você também pode criar uma função que recebe uma lista como entrada, em vez de usar raw_input(), e pode mudar '-'+`n`para `-n`. E agora que você está usando o Python 2, é possível remover os parênteses após o print.
mbomb007

Gerar a corda peça por peça é inteligente. Para economia de bytes, geralmente é mais curto fazer condicionais por seleção de lista ou aritmética, como def f(N):print''.join([' '+`n`,`-n`*(n+1 not in N)][n-1 in N]for n in sorted(N))[1:](que pode ser aprimorado).
Xnor

Você pode usar em set(N)vez de sorted(N); isso irá iterar corretamente do menor para o menor ao usar o cPython, mas não é garantido que funcione para todas as implementações; portanto, há alguma dúvida sobre se isso é válido ou não.
KSab

6

JavaScript (ES6): 171 154 140 137 bytes

Obrigado edc65 e vihan1086 pelas dicas! [...n]é muito bom, mas não funciona nesses casos devido a números com vários dígitos.

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


n.split sem parênteses é totalmente novo para mim! Mas [...n]é melhor
edc65

@ edc65 Obrigado, nunca pensei em desembalar a corda assim.
rink.attendant.6


... mas ... funciona com algum dos exemplos? existem números com vários dígitos; portanto, é necessário dividir um "" (espaço em branco) e não "" (sequência vazia). Eu provavelmente lhe deu a dica errada
edc65

@ edc65 Eu pensei que algo parecia diferente, então eu percebi que os casos de teste falharam. Ainda bom para aprender algo novo, embora
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

Esta é uma versão ligeiramente modificada de um exemplo nos documentos para slice_when .


4

CJam, 35 bytes

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

Experimente on-line no intérprete CJam .

Como funciona

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

Ruby, 70 bytes

Problemas como esses tendem a me fazer verificar a API do Ruby quanto a métodos adequados, e hoje descobri uma nova: Array#slice_whenintroduzida recentemente no Ruby v2.2 e aparentemente destinada a essa situação exata :)

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

Depois de classificar e fatiar adequadamente a matriz, ela pega cada sub-matriz e cria uma sequência a partir do elemento mais alto e mais baixo e, em seguida, une toda essa matriz em uma sequência.

Exemplo:

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


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

Muito ruim, mas novamente Prolog é uma péssima linguagem no golfe

Exemplo: a([9,13,3,11,8,4,10,15,6]).saídas3-4 6 8-11 13 15


3

CJam, 38 33 bytes

Nova versão, usando idéias e fragmentos de código sugeridos por @Dennis:

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

Experimente online

O formato de entrada é uma matriz CJam entre colchetes.

A idéia básica aqui é que eu subtraia uma sequência monotônica da sequência de entrada classificada primeiro:

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

Nessa diferença, os valores que fazem parte do mesmo intervalo têm o mesmo valor. A aplicação do operador CJam RLE a essa diferença enumera diretamente os intervalos.

Os valores sequenciais subtraídos precisam ser adicionados novamente durante a saída. Não estou totalmente feliz com como isso é feito no meu código. Eu suspeito que eu poderia salvar alguns bytes com uma maneira mais elegante de lidar com isso.

Para gerar a saída dos intervalos, isso usa a ideia de Dennis de gerar um número negativo para o valor final, que cuida da produção de a -, e também simplifica a lógica, porque apenas um valor precisa ser adicionado / omitido, dependendo do tamanho do intervalo .

Explicação:

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.

Esse é um uso inteligente do RLE! Tomando emprestado a manipulação de intervalo e o formato de entrada da minha resposta, você pode descer para 34 bytes:l~$_,,.-e`{~T+\_T+:T;,f+(\W>Wf*S}/
Dennis

Quando eu olhei originalmente para a sua solução, fiquei meio confuso como você entrava -na saída sem ela aparecer no código e sem uma condição. Agora entendi: isso vem da transformação do valor final em um número negativo! Eu nunca teria pensado nisso, então me sentiria mal por copiá-lo. Vou tentar aprender com isso na próxima vez! :)
Reto Koradi

Justo. Como cerca de l~$_,,.-e{~ T + _T +: T; (_ 2 $ + W * Q S?} / `Embora Isso é muito mais parecido com o seu próprio código e pesa apenas 33 bytes?.
Dennis

@ Dennis Ok, se você insistir. :) Na verdade, adotando a idéia principal de gerar um valor negativo para o final do intervalo, isso parece uma maneira razoavelmente direta de implementá-lo. Obrigado.
Reto Koradi

2

CoffeeScript, 178 161 bytes

Assim como minha resposta JavaScript. Preciso descobrir se o uso de compreensão resultará em código mais curto.

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

1

Python 2, 126 122 121 Bytes

Eu sei que isso pode ficar mais curto, só não sei onde. Requer entrada no formulário [#, #, #, #, ..., #].

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

Você parece encontrar soluções com execbastante frequência.
mbomb007

@ mbomb007 Você pode estar pensando no xnor :) E acho que nessa situação o loop pode ter o mesmo tamanho, ainda mais curto (ainda não brinquei com ele o suficiente).
Kade

1
Você poderá substituir while x<len(l)por while l[x:]para salvar alguns 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];}}}

Verifica os intervalos e os imprime de acordo. Infelizmente, tive que fazer um caso especial para o último elemento da matriz, pois o programa terminaria sem imprimir o último número ou intervalo.


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

Recebe entrada como uma matriz int, retorna a saída como uma lista de String separada por espaço

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.