Інтерпретувати нещільні діапазони


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}


Завдання полягає в наступному:

Вхідні дані

Масив символів та раніше визначений пункт діапазону у вигляді рядка

Вихідні дані

Елементи в 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-індекс замість 1-індексу як вхідний рядок? Тож застереження про діапазон стає "0 TO 2"=> {'H', 'e', 'l'}?
Kevin Cruijssen

У таблиці ASCII немає порожнього символу (за винятком недрукувальних). Що не так у використанні місця?
adrianmp

масив char - це в основному рядок, для цього порожні символи просто не будуть надруковані або повернені
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 . Ви можете замінити два пробіли для подвійного відступу одним вкладкою. Ви можете поставити код, наступний ifза тим же рядком, і розділити їх крапками з комою. І видаліть простір в [x] for. Крім того, 1if b else-1можна замінити будь-яким b and 1or-1або 2*bool(b)-1зберегти байт.
mbomb007

Спасибі! Я вже переглянув і (спробував) use.d деякі з них. Пізніше знову перегляньте всі відповіді. :)
1Darco1

І я думаю, ви можете використовувати неназваних lambda, оскільки це не рекурсивно.
mbomb007

1
t+=[int(x)]canbecomet+=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

Ось 117-байтне рішення, якщо ви скажете, що його ОБОВ'ЯЗКОВО індексувати на 1 замість 0: https://groovyconsole.appspot.com/edit/5205468955803648

Якщо ви хочете, щоб я поміняв оригінал на байт 113/117, дайте мені знати.


Якщо вам не подобається, що я використовую "nulls" для символів, які там відсутні, +5 байт в кінці для "-null", який видаляє всі нулі з набору.
Чарівна урва восьминога

1
Я люблю цей розумний збіг
downrep_nation

Я щось із цього навчився, але ніколи не знав, що Groovy мав Eval.me(...)досі; дано використовувати його на практиці було б смішно небезпечно, все-таки класно знати.
Чарівна восьминога урна

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

Скала, 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**9( 2357947691) враховуватиме діапазони, використовуючи ціле число min. Потім просто наріжте рядок, використовуючи зворотний зріз, якщо діапазон перевернуто.

З нульовою індексацією (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]]

Тепер для потворної частини - робота зі струнами в R, яка швидко заплутається. Спочатку ми визначаємо eяк порожній рядок (нам знадобиться це пізніше).

                      e<-""

Ми читаємо з stdin і перетворюємо рядок символів у масив окремих символів, розділяючи на порожній рядок. (Наприклад, ми переходимо від "Привіт" до ["H", "i"].) Це повертає список довжиною 1, тому нам потрібно попросити перший елемент [[1]]отримати масив, з яким ми можемо працювати. Фу, я попередив тебе, що це безладно.

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

R індексує, починаючи з 1, і має приємну особливість з від’ємними числами. Припустимо, xє ['a', 'b', 'c']. Виклик x[1]несподівано повертається 'a'. Виклик x[-1]повертає все , x крім індексу 1, тобто ['b', 'c']. Це класна особливість, але означає, що ми повинні бути обережними зі своїми негативними показниками цієї проблеми. Тому поки що ми просто повертаємо елементи вхідного масиву з індексом >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

Безіменна функція з двома параметрами, перший - масив символів (може бути і рядок), другий - рядок, що містить визначення діапазону.

Повернене значення - це масив, де кожен елемент може бути або одним символом, або 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на "І", розбиває кожний з отриманих підпунктів на "ДО", перетворює отримані рядки у intвикористання map. У кожному з результатів буде 1 або 2 пункти (1, якщо в підпункті немає "TO").
Побудує діапазони на основі 0 для кожного з них, використовуючи параметр кроку діапазону як 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, коли я збирався його подати.

Edit: прибраний простір з #(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для поділу на "І" та "", take-nthкраплі "TO" між цілими числами, відповідність аргументів функції обробляє випадок з 1 або 2 аргументів, і це стосується цього.

Конвенція про дзвінки: (f "Hello World" "1 TO 3 AND 2 AND 8 TO 2")


Ви можете видалити хек з великої кількості байтів, видаляючи пробіли взагалі, особливо між #символами.
клісмік

Ви впевнені, що я міг видалити пробіл між будь-яким #? Я пробував це без успіху, він "зливається" з попереднім жетоном. О, ще один простір для видалення %там.
NikoNyrh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.