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


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.