緩い範囲の解釈


13

緩い範囲の解釈

ListSharpは、多くの機能を備えたインタープリター型プログラミング言語です。これらの機能の1つは、次のように機能する1つのインデックスベースの範囲作成者です。

あなたはと範囲を定義する(INT) TO (INT)か、単に(INT)どこの両方または単一のintは分からに行くことができる最大の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}


課題は次のとおりです。

入力

文字配列および文字列として以前に定義された範囲句

出力

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
入力文字列として1インデックスの代わりに0インデックスを使用できますか?したがって、範囲句は"0 TO 2"=> {'H', 'e', 'l'}
ケビンCruijssen 16

ASCIIテーブルには空の文字はありません(印刷できない文字は除きます)。スペースの使用の何が問題になっていますか?
アドリアンプ

文字配列は基本的に文字列であるため、空の文字は印刷または返されません
-downrep_nation

1
また、たとえば、3 TO 3これまでに入力になり、予想される出力はどうなりますか?
ヨルダン

1
AND倍数範囲をテストするにはいくつかのテストケースが必要です。また、ほとんどの言語で標準であるゼロベースのインデックス作成を使用できるかどうかは回答しませんでした。
mbomb007

回答:


5

Python 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-1か、2*bool(b)-1バイトを保存します。
mbomb007

ありがとう!私はすでにそれらのいくつかを使用し、使用しようとしました。後ですべての回答をもう一度確認します。:)
1Darco1

そしてlambda、再帰的ではないので、名前のないを使用できると思います。
mbomb007

1
t+=[int(x)]canbecomet+=int(x),
チョイス

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 ","..") -toを従来の範囲に置き換えます。
  • .replaceAll(" AND ", ",") -すべてのandsをコンマに置き換えます。
  • "[${...}]" -Groovyの「リスト」表記で囲みます。
  • Eval.me(...) -文字列をGroovyコードとして評価します。
  • .flatten() -2D配列と1D配列の混合物を1D配列に平坦化します。
  • .collect{v[it]} -配列のインデックスを単一の構造に収集します。

次に、出力からヌルを削除する115 113バイトのソリューションを示します。 。https //groovyconsole.appspot.com/edit/5185924841340928

0ではなく1でインデックス付けする必要があると言う場合、117バイトのソリューションを次に示します。https : //groovyconsole.appspot.com/edit/5205468955803648

オリジナルを113/117バイトの1つと交換したい場合は、お知らせください。


存在しない文字に「null」を使用するのが気に入らない場合は、「-null」の末尾に+5バイトを追加すると、セットからすべてのnullが削除されます。
魔法のタコUr

1
この巧妙な偶然の一致が大好きです
-downrep_nation

私はこれから何かを学びましたが、今Eval.me(...)までGroovyが持っていたことを知りませんでした。実際にそれを使用することは、とんでもないほど安全ではありませんが、それでも知っておくべきことです。
魔法のタコUr

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

' '空の文字として使用してジョブを完了する、charリストを使用した単純なソリューション。すぐに改善したいと考えています。


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インデックスが許可されている場合、4バイト短くなります。

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のネガティブインデックスは文字列の末尾からインデックスを作成するため、2番目の値がある場合はそれi[-1]と同じi[0]か2番目の値を使用します。次に、負の範囲値をより負に調整する必要があるので、スライスが混乱しないようにします。負の値に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

2

R、142バイト

チャレンジを正しく理解したと仮定すると、ここでは rが文字列形式の定義済み範囲句であり、入力配列(例では「Hello world」)が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)

いくつかのテストケース:

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タイプ「式」に変換してからeval、式を評価するために呼び出します。結果の数値のシーケンスは、変数に再割り当てされますr

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

2行目

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

Nowい部分は、Rの文字列を処理することです。最初にe空の文字列として定義します(これは後で必要になります)。

                      e<-""

stdinから読み取り、空の文字列で分割することにより、文字列を個々の文字の配列に変換します。(たとえば、 "Hi"から["H"、 "i"]に移動します。)これは長さ1のリストを返すため、最初の要素[[1]]を要求して、処理可能な配列を取得する必要があります。うーん、これは面倒だと警告しました。

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

Rは1から始まるインデックスを作成し、負の数を使用する優れた機能を備えています。であるxとし['a', 'b', 'c']ます。呼び出しはx[1]当然戻ります'a'。呼び出しx[-1]は、インデックスをx 除くすべてを返します。これはクールな機能ですが、この問題の負のインデックスに注意する必要があることを意味します。そのため、ここでは、indexを使用して入力配列の要素を返し、結果をに割り当てます。1['b', 'c']>0o

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つのパラメーターを持つ名前のない関数。1つ目は文字配列(文字列でも可能)、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バイト

最初の引数として文字列、2番目の引数として範囲を指定して、コマンドラインでスクリプトを呼び出します。

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

すべてのテストは理想的です

s「AND」で句を分割し、「TO」で結果の各サブ句を分割し、結果の文字列をintusingに変換しmapます。結果にはそれぞれ1つまたは2つの項目があります(サブ節に「TO」が存在しない場合は1)。
インデックス0および-1の値を検査して、範囲のステップパラメーターを1または-1として使用して、これらのそれぞれに対して0から始まる範囲を構築します(1つのエントリを持つリストには、両方のインデックスにそのエントリがあります)。
提供されたインデックスが範囲内にある場合(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

間のスペースを削除しても#よろしいですか?私は成功せずに試しましたが、以前のトークンと「マージ」されます。ああ、もう1つスペース%があります。
ニコニール16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.