解释松散范围


13

解释松散范围

ListSharp是一种解释型编程语言,具有许多功能,其中一个功能是基于1索引的范围创建器,其工作方式如下:

您可以将范围定义为(INT) TO (INT)或仅定义(INT)两个int可以从min到max int32值的范围

然后,您可以使用这些范围来提取数组的元素,而不必担心会超出其边界


因此:

1 TO 5 产生: {1,2,3,4,5}

3 产生: {3}

范围可以使用AND运算符相加

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

记住这也适用于负数

3 TO -3 产生: {3,2,1,0,-1,-2,-3}


挑战如下:

输入值

字符数组和先前定义的range子句作为字符串

输出量

范围中基于1索引位置的元素(不存在/负索引会转换为空字符)


如何取胜

作为挑战,您应该创建具有最少字节数的程序以获胜


有人指出不存在空字符,因此您应该忽略它们(我仅在此处显示它们是为了使它们更易于理解,但却使人感到困惑)

测试用例:

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
是否允许使用0-index而不是1-index作为输入字符串?所以范围子句变成"0 TO 2"=> {'H', 'e', 'l'}
凯文·克鲁伊森

ASCII表没有空字符(不可打印的字符除外)。使用空间有什么问题?
adrianmp '16

一个char数组基本上是一个字符串,因此不会打印或返回空字符
downrep_nation

1
此外,例如3 TO 3将成为输入,预期输出是什么?
乔丹

1
您需要一些测试用例来AND计算倍数范围。另外,您也没有回答我们是否可以使用基于零的索引,这在大多数语言中都是标准的。
mbomb007'9

Answers:


5

蟒2 - 239个 211 210字节

感谢@ mbomb007@Cyoce为这个解决方案提供了更多帮助!

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

直截了当的方法。尝试了生成器和递归版本,但是它们无法在每个循环中都超越简单性。我是一个高尔夫菜鸟,所以很有可能会有所改善。而且,此代码段的主要缺陷在于,每次从字符数组中检索元素时,都会再次计算作为列表对象的范围(请参阅最后一行,列表理解)。这意味着r(s)执行len(r(s)) + 1时间。

取消程式码:

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

测试用例:

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

输出:

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

很棒的第一答案!欢迎来到PPCG!
mbomb007

您可能会受益于查看Python高尔夫技巧。您可以使用单个制表符替换2个空格以用于双缩进。您可以将代码if放在同一行之后,并用分号分隔。并删除中的空间[x] for。同样,1if b else-1可以替换为b and 1or-12*bool(b)-1保存一个字节。
mbomb007'9

谢谢!我已经看过并尝试使用其中的一些。稍后将再次查看所有答案。:)
1Darco1'9

而且我认为您可以使用unname lambda,因为它不是递归的。
mbomb007'9

1
t+=[int(x)]可能t+=int(x),
-Cyoce

3

Groovy(99 97字节)

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

在这里尝试:https : //groovyconsole.appspot.com/edit/5155820207603712

说明:

  • .replaceAll(" TO ","..") -将替换为传统范围。
  • .replaceAll(" AND ", ",") -用逗号替换所有ands。
  • "[${...}]" -用Groovy中的“列表”符号包围它。
  • Eval.me(...) -将字符串评估为Groovy代码。
  • .flatten() -将2D阵列和1D阵列的混合物展平为1D阵列。
  • .collect{v[it]} -将数组中的索引收集到单个结构中。

这里的一个115 113字节溶液从输出中除去空值: https://groovyconsole.appspot.com/edit/5185924841340928

如果您说必须将其索引为1而不是0,那么这是117字节的解决方案:https : //groovyconsole.appspot.com/edit/5205468955803648

如果您想让我将原来的113/117字节换成一个,请告诉我。


如果您不喜欢我不存在的字符使用“ nulls”,请在“ -null”的末尾添加+5个字节,这将从集合中删除所有null。
魔术章鱼缸

1
我喜欢这个聪明的巧合
downrep_nation

我从中学到了一些东西,Eval.me(...)直到现在还不知道Groovy有什么。在实践中使用它会显得非常不安全,这仍然是一件很酷的事情。
魔术章鱼缸

2

C#,342个字节

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

非高尔夫方法:

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

完整的测试用例程序:

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

一个幼稚的解决方案,使用字符列表,该字符列表' '用作空字符并完成工作。希望尽快改善。


2

Scala,165个字节

(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 "")

说明:

(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字节

我的回答有一些类似的想法,1Darco1的答案,但是通过使用从一开始就采用不同的方法(字符串的切片,而不是列表),它结束了一个相当短一些。如果允许使用0索引,则将缩短四个字节。

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

在线尝试

幸运的是,我可以将包含空格的字符串解析为整数。Python中的负索引从字符串的末尾开始索引,因此如果有一个值,我可以使用i[-1]等于i[0]或第二个值。然后,我必须将任何负范围值调整为更大的负值,以便它们不会与切片混淆。将负值乘以11**92357947691)将使用最小整数值说明范围。然后,只需将字符串切成薄片即可,如果范围反转,则使用反向切成薄片。

使用零索引(151字节):

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

做得好!切片绝对是这里的方法。我的range方法基本上只是一个超级冗长的形式。而且您甚至摆脱了整个if"T"in x: else:部分。+1
1Darco1 '16

2

R,142字节

假设我正确理解了挑战,这里我假设这r是字符串格式的预定义范围子句,并且从stdin中读取了输入数组(示例中为“ Hello world”)。

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)

一些测试用例:

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] "" ""

取消/解释

1号线

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

R有一个不错的中缀运算符:,可以生成序列。1:5给予[1, 2, 3, 4, 5]0:-2给予[0, -1, -2]。因此,我们将TO松散范围子句中的替换为:

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

解释AND只是串联。c为此,我们可以使用该函数,该函数可以方便地接受以逗号分隔的任意数量的参数。所以我们AND,

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

然后包裹在整个事情c()

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

这将产生一个看起来像的字符串c( 1 : 5 , 7 )。我们要求parse将convert转换为类型“ expression”,然后eval对表达式求值。然后将所得的数字序列重新分配给变量r

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

2号线

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

现在是丑陋的部分-处理R中的字符串,很快就会变得混乱。首先,我们定义e为空字符串(稍后将需要它)。

                      e<-""

我们从stdin中读取内容,并通过在空字符串处分割将字符串转换为单个字符的数组。(例如,我们从“ Hi”转到[“ H”,“ i”]。)这将返回一个长度为1的列表,因此我们必须要求第一个元素[[1]]获取可以使用的数组。gh,我警告过你,这太乱了。

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

R索引从1开始,并具有带负数的良好功能。假设x['a', 'b', 'c']x[1]毫不意外地打电话回来'a'。调用x[-1]返回x 索引以外的所有索引1,即['b', 'c']。这是一个很酷的功能,但是这意味着我们必须谨慎对待此问题的负面指标。因此,现在,我们只返回带有index的输入数组的元素>0,并将结果分配给o

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

3号线

但是,有一个问题!对于大于数组长度的索引,R仅返回NA值。我们需要它返回空字符串。因此,我们重新定义的元素o为这is.na(o)TRUE为空字符串。

o[is.na(o)]=e

4号线

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

最后,我们如何处理负(零)指数?它们都需要返回空字符串,因此我们将空字符串重复N次,其中N是的索引数<1

  rep(e,sum(r<1))

最后,我们将先前定义的o列表连接到此列表(可能为空)。

c(      ...      ,o)

2

JavaScript(ES6),141

具有2个参数的未命名函数,第一个是字符数组(可以是字符串),第二个是包含范围定义的字符串。

返回值是一个数组,其中每个元素可以是单个字符或js值undefined。字符串化后,这会导致一系列逗号分隔的未定义字符,显示为“空”字符-作为问题第一版中的测试用例。
使用.join,可以获得类似于当前版本问题中测试用例输出的字符串结果。

(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

少打高尔夫球

(
 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

测试

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个字节

在命令行中以字符串作为第一个参数,范围作为第二个参数来调用脚本。

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

消除混淆:

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字节

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

所有测试都在ideone

s在“ AND”上分割子句,在“ TO”上分割每个结果子句,将结果字符串转换为intusing map。结果将分别具有1或2个项目(如果子句中不存在“ TO”,则为1个项目)。
通过检查索引0和-1的值(范围为1的列表在两个索引处均具有该条目),使用range的步长参数作为1或-1为每个范围构造基于0的范围。
如果提供的索引在范围内(if 0<=i<len(a)),则遍历这些范围并构造输出列表。


0

果冻28 27 25 字节

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

TryItOnline(也可以使用字符串而不是char数组)

怎么样?

œṣ⁾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字节

哦,我创造的怪物是什么...但是实际上,当我要提交它时,它是260。

编辑:移除从空间#(get r %_"")(if_(< f t)(take-nth 2_%)(表示为_)。

(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 "))))))))

少打高尔夫球:

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

用于clojure.string/split通过“ AND”和“”进行拆分,take-nth在整数之间删除“ TO”,函数参数匹配处理1或2个参数的情况,并且与此有关。

调用约定: (f "Hello World" "1 TO 3 AND 2 AND 8 TO 2")


您通常可以通过删除空格来删除大量字节,尤其是在#字符之间。
clismique '16

您确定我可以删除两者之间的空格#吗?我尝试失败,它与先前的令牌“合并”在一起。哦,在%那之前还有一个空间要移走。
NikoNyrh '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.