Interpretar intervalos soltos


13

Interpretar intervalos soltos

ListSharp é uma linguagem de programação interpretada que possui muitos recursos, um deles é um criador de intervalo baseado em 1 índice que funciona assim:

Você define um intervalo como (INT) TO (INT)ou apenas (INT)onde ambos ou o int único podem ir do valor mínimo ao máximo int32

Em seguida, você pode usar esses intervalos para extrair elementos de uma matriz sem temer ultrapassar seus limites


Portanto:

1 TO 5 gera: {1,2,3,4,5}

3 gera: {3}

As faixas podem ser adicionadas usando o ANDoperador

1 TO 5 AND 3 TO 6 gera: {1,2,3,4,5,3,4,5,6}

lembre-se de que também funciona com números negativos

3 TO -3 gera: {3,2,1,0,-1,-2,-3}


O desafio é o seguinte:

Entrada

Uma matriz de caracteres e a cláusula de intervalo definido anteriormente como uma sequência

Resultado

Os elementos nos 1 locais com base no índice (índices inexistentes / negativos são convertidos em um caractere vazio)


Como ganhar

Como um desafio de , você deve criar o programa com a menor contagem de bytes para vencer


Foi apontado que caracteres vazios não existem; portanto, você deve ignorá-los (eu apenas os mostrei aqui para facilitar a compreensão e confundir as pessoas)

Casos de teste:

input array is:
{'H','e','l','l','o',' ','W','o','r','l','d'}

range clause:
"1 TO 3" => "Hel"
"5" => "o"
"-10 TO 10" => "Hello Worl"
"0 AND 2 AND 4" => "el"
"8 TO 3" => "oW oll"
"-300 AND 300" => ""
"1 TO 3 AND 3 TO 1" => "HelleH"
"-20 TO 0 AND 1 AND 4" => "Hl"

3
É permitido usar 0-index em vez de 1-index como string de entrada? Portanto, a cláusula range se torna "0 TO 2"=> {'H', 'e', 'l'}?
Kevin Cruijssen

A tabela ASCII não possui um caractere vazio (excluindo caracteres não imprimíveis). O que há de errado em usar o espaço?
adrianmp

uma matriz de caracteres é basicamente uma string; portanto, caracteres vazios não serão impressos ou retornados
downrep_nation

1
Além disso, por exemplo, 3 TO 3sempre será uma entrada e qual é o resultado esperado?
Jordan

1
Você precisa de alguns casos de teste para obter ANDvários intervalos. Além disso, você não respondeu se podemos usar a indexação com base em zero, o que é padrão na maioria dos idiomas.
mbomb007

Respostas:


5

Python 2 - 239 211 210 bytes

Obrigado a @ mbomb007 e @Cyoce por continuar jogando esta solução!

def r(s):
 t=[]
 for x in s.split("AND"):
  if"T"in x:a=map(int,x.split("TO"));b=2*(a[0]<a[1])-1;t+=range(a[0],a[1]+b,b)
  else:t+=int(x),
 return t
lambda p,v:[(['']+p+['']*max(map(abs,r(v))))[x]for x in r(v)]

Abordagem direta. Tentei geradores e uma versão recursiva, mas eles não conseguiram superar o simples para cada loop. Eu sou um noob de golfe, então isso provavelmente pode ser melhorado um pouco. Além disso, a principal falha desse snippet é que o intervalo como objeto de lista é calculado novamente sempre que um elemento é recuperado da matriz de caracteres (consulte a última linha, compreensão da lista). Isso significa que r(s)é executado len(r(s)) + 1vezes.

Código não destruído:

def find_range(string):
    result = []

    # Split at each AND and look at each element separately
    for element in string.split("AND"):
        # Element is just a number, so add that number to the result list
        if "TO" not in string:
            result += [int(string)]

        # Generate a list with all the values in between the boundaries 
        # (and the boundaries themselves, of course) and append it to the result list
        else:
            boundaries = map(int, string.split("TO"))
            ascending = boundaries[0] < boundaries[1]

            # range(start, stop, step) returns [start, ..., stop - 1], so extend the stop value accordingly
            # range(8, 3, 1) returns just [], so choose respective step (negative for a descending sequence)
            result += range(boundaries[0], boundaries[1] + (1 if ascending else -1), 1 if ascending else -1)

# Make the char array 1-indexed by appending an empty char in 0th position
# Add enough empty chars at the end so too large and negative values won't wrap around
interpret = lambda chars, range_expr: [(['']+chars+['']*max(map(abs, find_range(range_expr))))[x] for x in find_range(range_expr)]

Casos de teste:

c = list("Hello World")
print interpret(c, "1 TO 3")
print interpret(c, "5")
print interpret(c, "-10 TO 10")
print interpret(c, "0 AND 2 AND 4")
print interpret(c, "8 TO 3")
print interpret(c, "-300 AND 300")

Resultado:

['H', 'e', 'l']
['o']
['', '', '', '', '', '', '', '', '', '', '', 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l']
['', 'e', 'l']
['o', 'W', ' ', 'o', 'l', 'l']
['', '']

Ótima primeira resposta! Bem-vindo ao PPCG!
mbomb007

Você pode se beneficiar da exibição de Dicas para jogar golfe em Python . Você pode substituir 2 espaços para recuo duplo por uma única guia. Você pode colocar o código seguindo ifa mesma linha e separá-los com ponto e vírgula. E remova o espaço [x] for. Além disso, 1if b else-1pode ser substituído por um b and 1or-1ou 2*bool(b)-1para salvar um byte.
mbomb007

Obrigado! Eu já olhei e (tentei) usar.d alguns deles. Terá outra olhada em todas as respostas novamente mais tarde. :)
1Darco1

E acho que você pode usar um sem nome lambda, já que não é recursivo.
mbomb007

1
t+=[int(x)]canbecomet+=int(x),
Cyoce 30/09/16

3

Groovy ( 99 97 bytes)

{n,v->Eval.me("[${n.replaceAll(" TO ","..").replaceAll(" AND ",",")}]").flatten().collect{v[it]}}

Experimente aqui: https://groovyconsole.appspot.com/edit/5155820207603712

Explicação:

  • .replaceAll(" TO ","..") - Substitua o para por um intervalo tradicional.
  • .replaceAll(" AND ", ",") - Substitua todos os ands por uma vírgula.
  • "[${...}]" - Coloque-o na notação "list" no Groovy.
  • Eval.me(...) - Avalie a string como código Groovy.
  • .flatten() - Nivele a mistura da matriz 2D e da matriz 1D em uma matriz 1D.
  • .collect{v[it]} - Colete os índices da matriz em uma única estrutura.

Aqui está uma solução de 115 113 bytes que remove nulos da saída: https://groovyconsole.appspot.com/edit/5185924841340928

Aqui está uma solução de 117 bytes, se você disser que DEVE ser indexada em 1 em vez de 0: https://groovyconsole.appspot.com/edit/5205468955803648

Se você quiser que eu troque o original pelo de 113/117 bytes, informe-me.


Se você não gostar de mim usando "nulos" para os caracteres que não estão lá, +5 bytes no final para "-null", que remove todos os nulos do conjunto.
Magic Octopus Urn

1
Eu amo essa coincidência inteligente
downrep_nation

Eu aprendi algo com isso, porém, nunca soube que Groovy tinha Eval.me(...)até agora; dado que usá-lo na prática seria ridiculamente inseguro, ainda é uma coisa interessante de se saber.
Magic Octopus Urn

2

C #, 342 bytes

a=>r=>{var s=r.Replace(" AND","").Replace(" TO ","|").Split();int b=a.Length,i=0,n,m,j,o;var c=new List<char>();for(;i<s.Length;){var d=s[i++].Split('|');if(d.Length<2)c.Add(b<(n=int.Parse(d[0]))||n<1?' ':a[n-1]);else{o=(m=int.Parse(d[0]))<(n=int.Parse(d[1]))?1:-1;for(j=m;o>0?j<=n:j>=n;j+=o)c.Add(b<j||j<1?' ':a[j-1]);}}return c.ToArray();};

Método não destruído:

static char[] f(char[] a, string r)
{
    var s=r.Replace(" AND","").Replace(" TO ","|").Split();
    int b=a.Length,i=0,n,m,j,o;
    var c=new List<char>();
    for(;i<s.Length;)
    {
        var d=s[i++].Split('|');
        if(d.Length<2)
            c.Add(b<(n=int.Parse(d[0]))||n<1?' ':a[n-1]);
        else
        {
            o=(m=int.Parse(d[0]))<(n=int.Parse(d[1]))?1:-1;
            for(j=m;o>0?j<=n:j>=n;j+=o)
                c.Add(b<j||j<1?' ':a[j-1]);
        }
    }

    return c.ToArray();
}

Programa completo com casos de teste:

using System;
using System.Collections.Generic;

namespace InterpretLooseRanges
{
    class Program
    {
        static void PrintCharArray(char[] a)
        {
            for (int i=0; i<a.Length; i++)
                Console.Write(a[i]);
            Console.WriteLine();
        }

        static void Main(string[] args)
        {
            Func<char[],Func<string,char[]>>f= a=>r=>{var s=r.Replace(" AND","").Replace(" TO ","|").Split();int b=a.Length,i=0,n,m,j,o;var c=new List<char>();for(;i<s.Length;){var d=s[i++].Split('|');if(d.Length<2)c.Add(b<(n=int.Parse(d[0]))||n<1?' ':a[n-1]);else{o=(m=int.Parse(d[0]))<(n=int.Parse(d[1]))?1:-1;for(j=m;o>0?j<=n:j>=n;j+=o)c.Add(b<j||j<1?' ':a[j-1]);}}return c.ToArray();};

            char[] ar = {'H','e','l','l','o',' ','W','o','r','l','d'};

            PrintCharArray(f(ar)("1 TO 3"));
            PrintCharArray(f(ar)("5"));
            PrintCharArray(f(ar)("-10 TO 10"));
            PrintCharArray(f(ar)("0 AND 2 AND 4"));
            PrintCharArray(f(ar)("8 TO 3"));
            PrintCharArray(f(ar)("-300 AND 300"));
        }
    }
}

Uma solução ingênua, usando uma lista de caracteres, que usa ' 'como caractere vazio e faz o trabalho. Na esperança de melhorar em breve.


2

Scala, 165 bytes

(s:String,r:String)=>r split "AND"map(_ split "TO"map(_.trim.toInt))flatMap{case Array(a,b)=>if(a<b)a to b else a to(b,-1)
case x=>x}map(i=>s lift(i-1)getOrElse "")

Explicação:

(s:String,r:String)=> //define a function
r split "AND"         //split the range expression at every occurance of "AND"
map(                  //map each part...
  _ split "TO"          //split at to
  map(                  //for each of these splitted parts, map them to...
    _.trim.toInt          //trim all whitespace and parse as an int
  )                    
)                     //now we have an Array[Array[Int]]
flatMap{              //map each inner Array...
  case Array(a,b)=>if(a<b)a to b else a to(b,-1) //if it has two elements, create a Range
  case x=>x             //otherwise just return it
}                     //and flatten, so we get an Array[Int]
map(i=>               //for each int
  s lift(i-1)         //try to get the char with index i-1, since Scala is zero-based
  getOrElse ""        //otherwise return ""
) 

2

Python 2, 156 155 bytes

Minha resposta tem algumas idéias semelhantes, como de 1Darco1 resposta , mas usando uma abordagem diferente desde o início (corte corda ao invés de listas), acabou um pouco mais curto. Seria quatro bytes mais curto se a indexação 0 fosse permitida.

s,r=input()
o=""
for x in r.split("AND"):
    i=map(int,x.split("TO"));d=2*(i[0]<i[-1])-1
    for _ in-1,0:i[_]-=11**9*(i[_]<0)
    o+=s[i[0]-1:i[-1]+d-1:d]
print o

Experimente online

Felizmente, eu posso analisar cadeias contendo espaços em números inteiros. Indexação negativa em índices Python a partir do final da string, então eu uso i[-1]o mesmo i[0]ou o segundo valor, se houver. Então eu tenho que ajustar qualquer valor de intervalo negativo para mais negativo, para que eles não mexam com a fatia. Multiplicando valores negativos por11**9 ( 2357947691) considerará os intervalos usando o valor mínimo inteiro. Em seguida, basta cortar a corda, usando a fatia inversa, se o intervalo estiver invertido.

Com indexação zero (151 bytes):

s,r=input()
o=""
for x in r.split("AND"):
    i=map(int,x.split("TO"));d=2*(i[0]<i[-1])-1
    for _ in-1,0:i[_]-=11**9*(i[_]<0)
    o+=s[i[0]:i[-1]+d:d]
print o

Bom trabalho! Cortar definitivamente é o caminho a percorrer aqui. Minha rangeabordagem é basicamente apenas uma forma super detalhada de exatamente isso. E você até se livrou de toda a if"T"in x: else:parte. +1
1Darco1

2

R, 142 bytes

Supondo que entendi o desafio corretamente, aqui estou assumindo que essa ré a cláusula de intervalo predefinida no formato string e que a matriz de entrada ("Hello world", nos exemplos) é lida no stdin.

r=eval(parse(t=paste("c(",gsub("AND",",",gsub("TO",":",r)),")")))
o=strsplit(readline(),e<-"")[[1]][r[r>0]]
o[is.na(o)]=e
c(rep(e,sum(r<1)),o)

Alguns casos de teste:

r="1 TO 3"
[1] "H" "e" "l"

r="5"
[1] "o"

r="-10 TO 10"
[1] ""  ""  ""  ""  ""  ""  ""  ""  ""  ""  ""  "H" "e" "l" "l" "o" " " "w" "o" "r" "l"

r="0 AND 2 AND 4"
[1] ""  "e" "l"

r="8 TO 3"
[1] "o" "w" " " "o" "l" "l"

r="-300 AND 300"
[1] "" ""

Ungolfed / explicou

Linha 1

r=eval(parse(t=paste("c(",gsub("AND",",",gsub("TO",":",r)),")")))

R tem um bom operador de infix :que gera sequências. 1:5[1, 2, 3, 4, 5]e 0:-2[0, -1, -2]. Portanto, substituímos a TOcláusula no intervalo amplo por :.

                                         gsub("TO",":",r)

Interpretar ANDé apenas concatenação. Podemos usar a função cpara isso, que facilmente pode receber um número arbitrário de argumentos, separados por vírgula. Então substituímos ANDpor,

                          gsub("AND",",",      ...       )

e em seguida, enrole a coisa toda em c(, ).

               paste("c(",              ...               ,")")

Isso gera uma cadeia de caracteres que pode parecer c( 1 : 5 , 7 ). Chamamos parsea conversão para digitar "expressão" e, em seguida, evalpara avaliar a expressão. A sequência resultante de números é então atribuída novamente à variável r.

r=eval(parse(t=                     ...                        ))

Linha 2

o=strsplit(readline(),e<-"")[[1]][r[r>0]]

Agora, a parte mais feia - lidar com seqüências de caracteres em R, que fica confuso rapidamente. Primeiro, definimos ecomo uma string vazia (precisaremos disso mais tarde).

                      e<-""

Lemos do stdin e convertemos a cadeia de caracteres em uma matriz de caracteres individuais dividindo a cadeia vazia. (Por exemplo, passamos de "Oi" para ["H", "i"].) Isso retorna uma lista de comprimento 1, portanto, precisamos solicitar o primeiro elemento [[1]]para obter uma matriz com a qual possamos trabalhar. Ugh, eu avisei que isso era uma bagunça.

  strsplit(readline(), ... )[[1]]

Índices R começando em 1 e possui um bom recurso com números negativos. Suponha que xseja ['a', 'b', 'c']. Ligar x[1]sem surpresa retorna 'a'. A chamada x[-1]retorna todos, x exceto o índice 1, ou seja ['b', 'c']. Esse é um recurso interessante, mas significa que precisamos ter cuidado com nossos índices negativos para esse problema. Então, por enquanto, retornamos os elementos da matriz de entrada com o índice >0e atribuímos o resultado a o.

o=               ...             [r[r>0]]

Linha 3

No entanto, há um problema! Para índices maiores que o comprimento da matriz, R apenas retorna NAvalores. Precisamos que ele retorne cadeias vazias. Então, nós redefinir os elementos opara os quais is.na(o)é TRUEpara ser uma string vazia.

o[is.na(o)]=e

Linha 4

c(rep(e,sum(r<1)),o)

Finalmente, como lidamos com os índices negativos (e zero)? Todos eles precisam retornar a sequência vazia, portanto, repetimos a sequência vazia N vezes, em que N é o número de índices que são <1.

  rep(e,sum(r<1))

Por fim, concatenamos as definições definidas anteriormente. o para esta lista (potencialmente vazia).

c(      ...      ,o)

2

JavaScript (ES6), 141

Função sem nome com 2 parâmetros, o primeiro sendo a matriz de caracteres (também pode ser uma sequência), o segundo a sequência que contém a definição de intervalo.

O valor de retorno é uma matriz em que cada elemento pode ser um único caractere ou o valor de js undefined. Quando especificado, este resultado em uma sequência de caracteres separados por vírgula é indefinido, mostrado como o caractere "vazio" - como os casos de teste na primeira versão da pergunta.
Usando .joinvocê pode obter um resultado de sequência semelhante ao resultado do caso de teste na versão atual da pergunta.

(l,r,u,z=[])=>(r+' E').replace(/\S+/g,x=>x>'T'?u=t:x>'A'?[...Array((t-(w=(u=u||t)-(d=+u<t?1:-1)-1)-1)*d)].map(_=>z.push(l[w+=d]),u=0):t=x)&&z

Menos golfe

(
 l, r, // input paramaters, array/string and string
 u,    // local variable start at 'undefined'
 z=[]  // local variable, will contain the ouput
) => 
  (r+' E') // add an end marker
  .replace( /\S+/g, x=> // execute for each nonspace substring
    x > 'T' // check if 'TO'
    ? u = t // if 'TO' save first value in u (it's a string so even 0 is a truthy value)
    : x > 'A' // check if 'AND' or 'E'
      ? (
          u = u||t, // if u is falsy, it's a single value range t -> t
          d = +u < t ? 1 :-1, // direction of range up or down,comparison has to be numeric, so the leading +
          w = u - d - 1, // starting value (decrement by 1 as js array are 0 based)
          u = 0, // set u to falsy again for next round
          [...Array((t - w - 1) * d)] // build the array of required number of elements
          .map(_ => z.push(l[w+=d])) // iterate adding elements of l to z
        )
      : t = x // if not a keyword, save value in t
  ) && z // return output in z

Teste

f=
(l,r,u,z=[])=>(r+' E').replace(/\S+/g,x=>x>'T'?u=t:x>'A'?[...Array((t-(w=(u=u||t)-(d=+u<t?1:-1)-1)-1)*d)].map(_=>z.push(l[w+=d]),u=0):t=x)&&z

function run(x)
{
  R.value=x;
  O.textContent=f(L.value,x)
}

run("10 TO 5 AND 5 TO 10")
<table>
<tr><td>Base string</td><td><input id=L value="Hello World"></td></tr>
<tr><td>Custom range</td><td><input id=R ><button onclick='run(R.value)'>-></button></td></tr>
<tr><td>Output</td><td><pre id=O></pre></td></tr>
<tr><td>Test case ranges</td><td>
<select id=T onchange='run(this.value)'>
<option/>  
<option value="1 TO 3">1 TO 3 =&gt; {'H','e','l'}</option>
<option value="5">5 =&gt; {'o'}</option>
<option value="-10 TO 10">-10 TO 10 =&gt; {'','','','','','','','','','','','H','e','l','l','o',' ','W','o','r','l'}</option>
<option value="0 AND 2 AND 4">0 AND 2 AND 4 =&gt; {'','e','l'}
"8 TO 3" => {'o','W',' ','o','l','l'}</option>
<option value="-300 AND 300">-300 AND 300 =&gt; {'',''}</option>
<option value="1 TO 3 AND 3 TO 1">1 TO 3 AND 3 TO 1 =&gt; "HelleH"</option>
<option value="-20 TO 0 AND 1 AND 4">-20 TO 0 AND 1 AND 4 =&gt; "Hl"</option>
</select>
</td></tr>
</table>


1

Perl - 110 bytes

Chamar o script na linha de comando com a sequência como o primeiro argumento e o intervalo como o segundo.

for(split AND,pop@ARGV){$_>0?print+(split//,"@ARGV")[$_-1]:0for(/(.+)TO(.+)/?($1>$2?reverse$2..$1:$1..$2):$_)}

Desfocado:

for $subrange (split 'AND', $ARGV[1]) {
    for $index ($subrange =~ /(.+)TO(.+)/
        ? ($1 > $2 ? reverse $2..$1 : $1..$2) # All indices of that range
        : $subrange) # Otherwise, an index only
    {
        if ($index > 0) {
            # Here, 'split' returns an array of all characters
            print((split //, $ARGV[0])[$index - 1]);
        }
    }
}

1

Python 2, 146 bytes

lambda s,a:[a[i]for x in[map(int,c.split('TO'))for c in s.split('AND')]for i in range(x[0]-1,x[-1]-2*(x[-1]<x[0]),1-2*(x[-1]<x[0]))if 0<=i<len(a)]

Todos os testes estão no ideone

Divide a cláusula, sem "AND", divide cada uma das subcláusulas resultantes em "TO", converte as seqüências resultantes em intuso map. Os resultados terão cada um 1 ou 2 itens (1 se nenhum "TO" estiver presente na subcláusula).
Constrói intervalos com base em 0 para cada um deles usando o parâmetro step do intervalo como 1 ou -1, inspecionando os valores nos índices 0 e -1 (uma lista com uma entrada possui essa entrada nos dois índices).
Percorre esses intervalos e constrói uma lista da saída, se os índices fornecidos estiverem dentro do intervalo ( if 0<=i<len(a)).


0

Geléia , 28 27 25 bytes

œṣ⁾TOj”rV
œṣ“Ñþ»Ç€Ff⁹J¤ị⁹

TryItOnline (também funcionará com uma string em vez de uma matriz de caracteres)

Quão?

œṣ⁾TOj”rV - Link 1, construct sub-range: subclause
  ⁾TO     - string "TO"
œṣ        - split on sublists
     j    - join with
      ”r  - character "r"
        V - evaluate as Jelly code
                (r is the Jelly dyad for inclusive range, which works just like TO
                 when no r is present the string evaluates to the number:
                 " -20 "       evaluates to -20;
                 " -20 r -19 " evaluates to [-20,-19];
                 " 3 r -3 "    evaluates to [3,2,1,0,-1,-2,-3]; etc.)

œṣ“Ñþ»Ç€Ff⁹J¤ị⁹ - Main link: range clause, array 
  “Ñþ»          - compression of the string "AND"
œṣ              - split on sublists
      ǀ        - call the last link (1) as a monad for each
        F       - flatten list
            ¤   - nilad and link(s) as a nilad
          ⁹     - right argument (the array)
           J    - range for length [1,2,...,len(array)]
         f      - filter keep
                      (Jelly indexing is modular so keep only in-bound indexes)
             ị⁹ - index into the array

0

Clojure 232 230 229 bytes

Oh, que monstro eu criei ... Mas, na verdade, era 260 quando eu estava prestes a enviá-lo.

Editar: removido um espaço de #(get r %_""), (if_(< f t)e (take-nth 2_%)(como indicado _).

(let[S clojure.string/split](fn[r s](apply str(map #(get r %"")(mapcat #(apply(fn([f][(dec f)])([f t](if(< f t)(range(dec f)t)(reverse(range(dec t)f)))))%)(map #(mapv read-string(take-nth 2%))(map #(S % #" ")(S s #" AND "))))))))

Menos golfe:

(def f (let[S clojure.string/split]
         (fn[r s] (->> (map #(S % #" ") (S s #" AND "))
                       (map #(mapv read-string (take-nth 2 %)))
                       (mapcat #(apply(fn
                                        ([f][(dec f)])
                                        ([f t](if (< f t)
                                                (range (dec f) t)
                                                (reverse (range (dec t) f)))))  %))
                       (map #(get r % ""))
                       (apply str)))))

Usa clojure.string/splitpara dividir por "AND" e "",take-nth descarta "TO" entre números inteiros, a correspondência de argumentos de função lida com o caso de 1 ou 2 argumentos e é isso.

Convenção de chamada: (f "Hello World" "1 TO 3 AND 2 AND 8 TO 2")


Você pode remover muitos bytes removendo espaços em geral, especialmente entre os #caracteres.
Clismique

Tem certeza de que eu poderia remover um espaço entre eles #? Eu tentei sem sucesso, ele é "mesclado" com o token anterior. Ah, mais um espaço para remover antes de %lá.
NikoNyrh
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.