Превратите массив в математическую задачу


35

Учитывая непустой список неотрицательных целых чисел, рассмотрите переписывание его как арифметическую задачу, где:

  • Знак плюс ( +) вставляется между парами чисел, которые увеличиваются слева направо (то есть от начала списка до конца).
  • Знак минус ( -) вставляется между парами чисел, которые уменьшаются слева направо.
  • Знак умножения ( *) вставляется между парами чисел, которые равны.

Сказано иначе: любой подсписок a,bстановится a+bif a<b, a-bif a>bи a*bif a==b.

Например, список

[12, 0, 7, 7, 29, 10, 2, 2, 1]

станет выражением

12 - 0 + 7*7 + 29 - 10 - 2*2 - 1

который оценивает 75 .

Напишите программу или функцию, которая берет такой список и оценивает его, печатая или возвращая результат.

  • Порядок операций имеет значение. Умножение должно быть сделано перед любым сложением или вычитанием.
  • Если у входного списка есть одно число, это должно быть то, к чему он оценивает. например [64]должен дать 64.
  • Использование evalили execили подобных конструкций не допускается.

Вот несколько дополнительных примеров:

[list]
expression
value

[0]
0
0

[1]
1
1

[78557] 
78557
78557

[0,0]
0*0
0

[1,1]
1*1
1

[2,2]
2*2
4

[0,1]
0+1
1

[1,0]
1-0
1

[1,2]
1+2
3

[2,1]
2-1
1

[15,4,4]
15-4*4
-1

[9,8,1]
9-8-1
0

[4,2,2,4]
4-2*2+4
4

[10,9,9,12]
10-9*9+12
-59

[1,1,2,2,3,3]
1*1+2*2+3*3
14

[5,5,4,4,3,3]
5*5-4*4-3*3
0

[3,1,4,1,5,9,2,6,5,3,5,9]
3-1+4-1+5+9-2+6-5-3+5+9
29

[7637,388,389,388,387,12,0,0,34,35,35,27,27,2]
7637-388+389-388-387-12-0*0+34+35*35-27*27-2
7379

Самый короткий код в байтах побеждает. Tiebreaker - более ранний ответ.


5
Относительно «порядка операций имеет значение», возможно, было бы хорошо четко указать, что сложение и вычитание являются левоассоциативными и имеют одинаковый приоритет.
— Мартин Эндер

Ответы:


15

Python 2, 63 байта

p=s='print-'
for x in input():s+='*+-'[cmp(x,p)]+`x`;p=x
exec s

Создает и evalвыражает строку выражения. Арифметический символ выбирается путем сравнения предыдущего числа pс текущим x. После символа добавляется текущий номер.

Первый номер обрабатывается умным трюком из Sp3000. Начальное значение pустанавливается в строку, которая больше любого числа и поэтому вызывает -перед первым числом. Но, sинициализируется print-в то же самое время, что и результат, начинающийся с print--(спасибо xsot за сохранение 2 байтов путем инициализации с print.)


Я думаю, что вы можете перейти printв строку и использовать execвместо eval.
— xsot

13

Pyth, 31 26 19 17 16 15 байт

Выражения с *не будут оцениваться в Интернете, но теоретически они будут работать.

2 байта благодаря Maltysen.

vsm+@"*-+"._-~k

Тестовый пакет (с оценкой).

Другие случаи (без оценки).

история

  • 31 байт: M+G@"*-+"->GH<GHv+sgMC,JsMQtJ\x60e
  • 26 байт: M+G@"*-+"->GH<GHv+sgVQtQ\x60e
  • 19 байтов: vtssVm@"*-+"->Zd<~Z
  • 17 байтов: vtssVm@"*-+"._-~Z
  • 16 байтов: vssVm@"*-+"._-~k
  • 15 байтов: vsm+@"*-+"._-~k

Почему умножение не работает онлайн? Если вы не уверены, что это работает, может быть лучше проверить немного больше, прежде чем ответить.
— Увлечения Кельвина

Потому что безопасность вещи (оценка работает только для +и -онлайн)
— Leaky Nun

@HelkaHomba У меня еще не было возможности попробовать его в автономном режиме, но он должен работать. Онлайн-переводчик использует --safeпереключатель, который заменяется evalна ast.literal_eval.
— Деннис

Хорошо, достаточно справедливо.
— Увлечения Кельвина

Подтверждено, что это работает с автономным переводчиком.
— Деннис

12

Желе , 18 16 15 14 байт

I0;ð1g×⁹⁸œṗP€S

Не использует встроенный Eval. Попробуйте онлайн! или проверьте все контрольные примеры .

Как это работает

I0;ð1g×⁹⁸œṗP€S  Main link. Input: A (list)

I               Increments; compute the deltas of all adjacent items of A.
 0;             Prepend a 0.
   ð            Begin a new, dyadic chain.
                Left argument: D (0 plus deltas). Right argument: A
    1g          Compute the GCD of 1 and each item in D.
                This yields 1 for non-negative items, -1 for negative ones.
      ×⁹        Multiply each 1 or -1 with the corresponding item of A.
                This negates every item in A that follows a - sign.
        ⁸œṗ     Partition the result by D. This splits at occurrences of non-zero
                values of D, grouping items with identical absolute value.
           P€   Take the product of each group.
             S  Sum; add the results.


1
Красиво сделано. Я должен добавить Python evalкак атом ...
— Деннис

9
Я вышел из игры в гольф. : P
— Деннис

Хорошо сделано, ваша очередь!
— Дрянная Монахиня

9

MATL , 12 байт

Y'^l6MdZSh*s

Здесь используется очень хорошая идея @ aditsu о кодировании длин серий.

Попробуйте онлайн!

объяснение

       % Take input vector implicitly
Y'     % RLE. Produces two vectors: values and lengths
^      % Rise each value to the number of consecutive times it appears. This
       % realizes the product of consecutive equal values
l      % Push 1
6M     % Push vector of values again
d      % Consecutive differences
ZS     % Sign function. Gives 1 or -1 (no 0 in this case)
h      % Concatenate horizontally with previous 1
*      % Multiply. This gives plus or minus depending on increasing character
s      % Sum of vector. This realizes the additions or subtractions
       % Display implicitly

Хаха, только что написал что-то подобное. RLE хорошо работает для этого
— Suever

@ Как бы там ни было :-D
— Луис Мендо

7

CJam, 20

q~e`{~_W-g\:W@#*}%:+

Попробуйте онлайн

Объяснение:

q~       read and evaluate the input (array of numbers)
e`       RLE encode, obtaining [count number] pairs
{…}%     map each pair
  ~_     dump the count and number on the stack, and duplicate the number
  W-     subtract the previous number (W is initially -1 by default)
  g      get the sign of the result
  \      swap with the other copy of the number
  :W     store it in W (for next iteration)
  @#     bring the count to the top, and raise the number to that power
  *      multiply with the sign
:+       add all the results together

7

JavaScript (ES6), 54

p=>eval(0+p.map(v=>x+='*-+'[(p>v)+2*(p<v)]+(p=v),x=1))

eval получает список выражений через запятую и возвращает значение последнего.

Тест

f=p=>eval(0+p.map(v=>x+='*-+'[(p>v)+2*(p<v)]+(p=v),x=1))

t=p=>(0+p.map(v=>x+='*-+'[(p>v)+2*(p<v)]+(p=v),x=1))

function Test() {
  var a=I.value.match(/\d+/g).map(x=>+x) // convert input to a numeric array
  
  var x=f(a),y=t(a)
  O.textContent='Value '+x+'\n(no eval '+y+')'
}  

Test()
#I { width:80%}
<input value='12, 0, 7, 7, 29, 10, 2, 2, 1' id=I>
<button onclick='Test()'>Test</button>
<pre id=O></pre>


4
Это худшее злоупотребление оператором запятой, которое я помню, видя на этом сайте ...
— Нил

5

Юлия, 76 57 байт

!x=[[" ""-*+"[2+sign(diff(x))]...] x]'|>join|>parse|>eval

Я впервые играю в гольф с Джулией, так что, возможно, есть очевидные улучшения. Попробуйте онлайн!

Деннис сэкономил тонну байтов.


Хорошая работа. Я не знал, что вы можете определить пользовательскую функцию для !.
— Rɪᴋᴇʀ


4

Пиф - 23 22 20 байт

Как и в случае с Кенни, умножение не работает онлайн.

vs.i+\+@L"*+-"._M-Vt

Тестовый набор, не делая eval .



@LeakyNun Через некоторое время я забыл твое имя> _>
— Малтысен

@Maltysen Хаха, ты думаешь о Кевине-не-Кенни Лау
— DJMcMayhem

Извините, я ел, поэтому я не мог сыграть в гольф свое решение. Твой ход.
— Дрянная Монахиня

@LeakyNun почти там
— Maltysen

3

R, 92 байта

Скорее всего, здесь еще есть хороший гольф.

eval(parse(t=paste(i<-scan(),c(ifelse(d<-diff(i),ifelse(d>0,"+","-"),"*"),""),collapse="")))

Ungolfed:

i = scan()                # Read list from stdin
d = diff(i)               # Calculate difference between each element of list
s = ifelse(d,             # If d!=0
             ifelse(d>0,  # And if d>1
                    "+",  # Return plus
                    "-"), # Else return minus
             "*")         # Else (i.e. d==0) return multiply.
s = c(s,"")               # Pad the list s with an empty string, so it's the same
                          # length as i
p = paste(i,s,collapse="")# Paste the elements of i and s into one long string.
eval(parse(t=p))          # Evaluate the string as a language object.

Мне удалось сохранить только один байт, используя подход индексации
— JayCe


2

TI-BASIC, 146 байтов

Я буду хорошо отформатировать, когда не на мобильном телефоне. Сон ускользает от меня, так что вы получите это. Наслаждаться.

Prompt L₁
"(→Str1
For(A,1,dim(L₁
{0,1→L₂
{0,L₁(A→L₃
LinReg(ax+b) L₁,L₃,Y₁
Equ►String(Y₁,Str2
sub(Str2,1,-1+inString(Str2,"X→Str2
If A>1
Then
L₁(A-1
2+(Ans>L₁(A))-(Ans<L₁(A
Str1+sub("+*-",Ans,1→Str1
End
Str1+Str2→Str2
End
expr(Str1

2

Javascript ES6, 64 62 символа

a=>eval(a.map((x,i)=>x+('*+-'[x<a[++i]|(x>a[i])*2])).join``+1)

3
Разве это не должно быть функцией и aпараметром?
— edc65

Это неверно как есть.
— Rɪᴋᴇʀ

@ edc65, да, так и должно быть. Но на самом деле это было посчитано (указано 61, а реальная длина кода была 59), я просто плохо скопировал новый код (редактирование должно быть a[i+1]...a[i+1]=> a[++i]...a[i]- на 2 символа короче, но я по ошибке заменил весь сброс кода a=>).
— Qwertiy

@ EᴀsᴛᴇʀʟʏIʀᴋ, это просто неправильная паста. Смотрите комментарий выше и редактируйте историю для более подробной информации.
— Qwertiy

@Qwertiy хорошо, круто. Хороший ответ, кстати ..
— Rɪᴋᴇʀ

1

Java, 384 байта

int s(int[]l){int n=l[0],m;for(int i=0;i<l.length-1;i++)if(l[i]<l[i+1])if(i<l.length-2&&l[i+1]!=l[i+2])n+=l[i+1];else{m=l[i+1];while(i<l.length-2&&l[i+1]==l[i+2])m*=l[(i++)+1];n+=m;}else if(l[i]>l[i+1])if(i<l.length-2&&l[i+1]!=l[i+2])n-=l[i+1];else{m=l[i+1];while(i<l.length-2&&l[i+1]==l[i+2])m*=l[(i++)+1];n-=m;}else{m=l[i];while(i<l.length-1&&l[i]==l[i+1])m*=l[i++];n+=m;}return n;}

Ungolfed попробуйте онлайн

int s(int[] l)
{
    int n=l[0], m;

    for(int i=0; i<l.length-1; i++)
    {
        if(l[i] < l[i+1])
        {
            if (i<l.length-2 && l[i+1]!=l[i+2])
            {
                n += l[i+1];
            }
            else
            {
                m = l[i+1];
                while(i<l.length-2 && l[i+1]==l[i+2]) m *= l[(i++)+1];
                n += m;
            }
        }
        else if(l[i] > l[i+1])
        {
            if (i<l.length-2 && l[i+1]!=l[i+2])
            {
                n -= l[i+1];
            }
            else
            {
                m = l[i+1];
                while(i<l.length-2 && l[i+1]==l[i+2]) m *= l[(i++)+1];
                n -= m;
            }
        }
        else
        {
            m = l[i];
            while(i<l.length-1 && l[i]==l[i+1]) m *= l[i++];
            n += m;
        }
    }

    return n;
}

1
Некоторые быстро гольфы: int a=l.length, &&=> &, поставить int i=0на одной и той же «линии» , как int n=l[0],m.
— Утренняя монахиня

В if(i<l.length-2&&l[i+1]!=l[i+2])n+=l[i+1];else{m=l[i+1];while(i<l.length-2&&l[i+1]==l[i+2])m*=l[(i++)+1];n+=m;, вы можете просто заменить это содержимое внутри elseблока.
— Утренняя монахиня

1

Javascript ES6, 79 символов

a=>eval(`${a}`.replace(/(\d+),(?=(\d+))/g,(m,a,b)=>a+('*+-'[+a<+b|(+a>+b)*2])))

1

Perl, 49 байт

Код 48 байтов + 1 для -p

s/\d+ (?=(\d+))/$&.qw(* - +)[$&<=>$1]/ge;$_=eval

использование

perl -pe 's/\d+ (?=(\d+))/$&.qw(* - +)[$&<=>$1]/ge;$_=eval' <<< '12 0 7 7 29 10 2 2 1'
75

Заметки

Здесь я узнал, что вы можете запечатлеть взгляд в PCRE, хотя он немного не интуитивен ( (?=(\d+))вместо ((?=\d+))). Это имеет смысл после прочтения, так как вы будете захватывать совпадение нулевой длины (прогноз) с последним, а вместо этого захватывать совпадение с первым).

Спасибо @ninjalj за сохранение 8 байтов!


@LeakyNun Я никогда точно не знаю, на что рассчитывать, я не могу найти соответствующий мета-пост, я счастлив увеличить счет, но я подумал, что, так как вы можете работать с -eбесплатно, добавив, что pсоздание -peбыло +1 ? Будет обновляться сейчас, но если бы вы могли найти источник, который я мог бы процитировать / ссылку для продвижения вперед, это было бы здорово!
— Дом Гастингс

3
@DomHastings 1 правильный, по той причине, по которой вы говорите + этот мета-пост
— Sp3000

Спасибо @ Sp3000! Я не мог найти этот пост на всю жизнь! @LeakyNun мета пост для +1 согласно комментарию от Sp3000
— Дом Гастингс

Вместо использования цепных условных операторов вы можете использовать оператор космического корабля для выбора из списка: $&.qw(* - +)[$&<=>$1]в замещающей части s///оператора.
— ниндзя

@ninjalj Конечно! удивительно, спасибо! -8 с этим!
— Дом Гастингс

1

На самом деле, 30 байтов

;2@VpXdX`i-su"+*-"E`M' @o♀+εj≡

К сожалению, потому что Eval (≡ ) оценивает литералы только на TIO, эта программа не работает на TIO.

Объяснение:

;2@VpXdX`i-su"+*-"E`M' @o♀+εj≡
;                               duplicate input
 2@V                            overlapping sublists of length <= 2
    pXdX                        discard first and last element (length-1 sublists)
        `i-su"+*-"E`M           map: for each pair of elements
         i-su                     flatten, subtract, sign, increment (results in a 0 if b < a, 1 if b == a, and 2 if b > a)
             "+*-"E               select the correct operation
                     ' @o       put a space at the beginning of the list to pad it properly
                         ♀+     pairwise addition (since addition is not defined for strings and integers, this just zips the lists and flattens the result into a single flat list)
                           εj   join with empty string
                             ≡  eval

1

R , 120 44 байта

r=rle(scan());c(1,sign(diff(r$v)))%*%r$v^r$l

Попробуйте онлайн!

Алгоритм похож на этот ответ , но я понял это только после написания своего ответа. Гораздо лучше, чем мой оригинальный ответ, который использовал eval(parse).

Полностью использует векторизованные операции R - *сначала делает операцию, используя rle(x)$values ^ rle(x)$lenghtsи sign( diff( rle(x)$values ) )расставляет точки на этот вектор (с префиксом 1).


1

05AB1E (legacy) , 17 16 15 байтов

ü.S…*-+sè‚ζJJ.E

-2 байта благодаря @Emigna .

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

ü                  # Pair-wise loop over the (implicit) input-list
                   #  i.e. [12,0,7,7] → [[12,0],[0,7],[7,7]]
 .S                # Calculate the signum of the pair (-1 for a<b; 0 for a==b; 1 for a>b)
                   #  i.e. [[12,0],[0,7],[7,7]] → [1,-1,0]
   …*-+sè          # Index over "*-+" (with wrap-around)
                   #  i.e. [1,-1,0] → ['-','+','*']
         ‚ζ        # Zip the two lists together (appending the operands to the numbers)
                   #  i.e. [12,0,7,7] and ['-','+','*','+']
                   #   → [[12,'-'],[0,'+'],[7,'*'],[7,' ']]
           JJ      # Join them together
                   #  [[12,'-'],[0,'+'],[7,'*'],[7,' ']] → '12-0+7*7 '
             .E    # Evaluate as Python code
                   #  i.e. '12-0+7*7' → 61

1
Благодаря модульной индексации вы можете удалить >, переместившись +в конец строки.
— Эминья

@ Emigna Не знаю, как я это пропустил .. Спасибо!
— Кевин Круйссен

1
Вы можете сохранить еще один байт, удалив Ćи ¨, если вы используете ‚ζвместоø
— Emigna

@ Emigna О, теперь это умно! Спасибо. Я знал, что вложение было немного странным, но не знал, как это исправить. ‚ζэто идеальный альтернативный обходной путь, так как пространство игнорируется в eval. Еще раз спасибо. :)
— Кевин Круйссен

0

PHP, 103 байта

Аккуратный вызов. Это дольше, чем ожидалось. Я думаю, что использование array_mapили подобное не улучшит число байтов, так как анонимные функции все еще дороги в PHP.

foreach(fgetcsv(STDIN)as$v)(0<=$p?$o.=$p.('*-+'[($p>$v)+2*($p<$v)]):_)&&$p=$v;echo eval("return$o$v;");

Запускается из командной строки, запрашивает список через запятую, например:

php array_to_math.php
12, 0, 7, 7, 29, 10, 2, 2, 1

0

PowerShell v2 +, 62 байта

-join($args|%{"$o"+'*+-'[($o-lt$_)+2*($o-gt$_)];$o=$_})+$o|iex

Принимает ввод как разделенные пробелами аргументы командной строки, которые преобразуются в автоматический массив $args. Перебираем каждый элемент, используя вспомогательную переменную$o каждую итерацию, чтобы вспомнить, какой была наша предыдущая запись. Мы используем индексированную строку, чтобы вытащить соответствующий оператор, выполняя математические операции с неявно преобразованными логическими значениями (например, если предыдущая запись меньше, []вычисление 1+2*0так '*+-'[1]означает, что+ выбран).

Связанные строки остаются на конвейере. Мы собираем все эти фрагменты вместе (например, 3-, 1+, 4-и т.д.) с -joinработой, можно сцепить на конечном числе (неявно преобразуется в строку), а также через канал, iex(псевдоним для Invoke-Expressionи подобного eval).


Проблема заключается в том, что если вызывающая сторона уже указала значение $ oa (скажем, $ o = 999), то выражение в этой записи не будет вычислять правильное значение. Инициализация $ o должна быть добавлена ​​к этому решению.
— Бево

@Bevo Это полный сценарий, выполняемый через командную строку, а не функция или интерактивная оболочка. Подавляющее большинство моих представлений как таковых, поскольку в таком сценарии нет предопределенных переменных, о которых нужно беспокоиться, и, следовательно, код может быть немного короче.
— AdmBorkBork


0

Japt -x , 21 19 байт

änJ f mÎí*Uò¦ ®ÎpZÊ

Попытайся


объяснение

                        :Implicit input of array U
  J                     :Prepend -1
än                      :Get deltas
    f                   :Filter (remove 0s)
      m                 :Map
       Î                : Signs
        í               :Interleave
          U             :  Original input
           ò            :  Partition on
            ¦           :   Inequality
              ®         :  Map each sub-array Z
               Î        :    Get first element
                p       :    Raise to the power of
                 ZÊ     :     Length of Z
         *              :Reduce each pair of elements by multiplcation
                        :Implicitly reduce by addition and output
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.