Подсчитать изменения в массиве

20

Ваша задача сегодня состоит в том, чтобы написать программу или функцию, которая принимает массив целых чисел и подсчитывает, сколько раз, читая его слева направо, изменяется значение. Это проще показать на примере:[1 1 1 2 2 5 5 5 5 17 3] => [1 1 1 **2** 2 **5** 5 5 5 **17** **3**] => 4

Прецедент:

Input           |   Output
[]              |   0
[0]             |   0
[0 1]           |   1
[0 0]           |   0
[1 2 3 17]      |   3
[1 1 1 2 2 3]   |   2
[-3 3 3 -3 0]   |   3

Это , побеждает меньше байтов!

Павел
источник
Является ли мой ответ действительным, если результат всегда правильно рассчитан, но если он Falseравен 0, печатается вместо него?
FlipTack
1
@FlipTack Это зависит от языка. В общем, если я могу сказать, 2+Falseи это ошибки, это не хорошо, но если я получу 2, это нормально.
Павел
@FlipTack По умолчанию это консенсус.
полностью человек
Является ли пустой вывод 0приемлемым?
Тит
@ Да, это так.
Павел

Ответы:

9

Python 3 , 38 байт

f=lambda x=0,*y:y>()and(x!=y[0])+f(*y)

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

Деннис
источник
2
Да, знал, что вы можете использовать аргумент по умолчанию, хороший поиск.
xnor
Более
простой
@Dennis Как функция выходит из рекурсивного цикла, когда массив пуст? Я не вижу , как это не заканчивается в maximum recursion depth exceeded.
Иоанн
@Ioannes После того, как остался только один элемент ( x ), y>()он оценивается как False , поэтому следующий код andне выполняется.
Деннис
7

Haskell , 33 байта

f(a:b:r)=sum[1|a/=b]+f(b:r)
f _=0

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


Бонус: довольно любопытная бессмысленная арифметическая версия (44 байта)

sum.(tail>>=zipWith((((0^).(0^).abs).).(-)))

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

Учитывая вход [1,1,4,3,3,3], мы сначала берем разницу смежных записей ( [0,3,-1,0,0]), то absolute значения: [0,3,1,0,0]. Принятие нуля к мощности каждого элемента дает первый раз [1,0,0,1,1], а второй раз инвертирует список: [0,1,1,0,0]( (1-)здесь также будет работать вместо (0^)). Наконец мы берем sumсписок, чтобы получить 2.

Laikoni
источник
5

Brain-Flak , 50 байтов

([][()]){{}({}[({})]){{}<>({}())(<>)}{}([][()])}<>

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

Ничего не выводит для 0, что в мозге-флак эквивалентно. Если это не приемлемо, тогда добавьте это для +4байтов:({})

Объяснение:

#Push stack-height-1
([][()])

#While true:
{

    #Pop the stack-height-1 off
    {}

    #If 'a' is the element on top of the stack, and 'b' is the element underneath it, then
    #Pop 'a' off, and push (a - b)
    ({}[({})])

    #If (a-b) is not 0...
    {
        #Pop (a-b) off
        {}

        #Switch stacks
        <>

        #Increment the value on the other stack
        ({}())

        #Push a 0 back to the main stack
        (<>)

    #Endif
    }

    #Pop either (a-b) or the 0 we pushed
    {}

    #Push stack-height-1
    ([][()])

#Endwhile
}

#Toggle to the alternate stack and display the counter
<>
DJMcMayhem
источник
@ Райли Отлично сделано! :)
DJMcMayhem
1
@WheatWizard Я тоже это попробовал, но он всегда зацикливается на пустом вводе. -0+1 = 1
H.PWiz
5

Brain-Flak , 50 байтов

(([][()]){[{}]<({}[({})])>{(<{}>)()}{}([][()])}<>)

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

# Get ready to push the answer
(

# Push stack height - 1
([][()])

# Loop until 0 (until the stack has a height of 1)
{

  # Pop the old stack height and subtract it 
  #(cancels the loop counter from the final answer)
  [{}]

  # Pop the top of the stack and subtract the next element from that
  # Don't include this in the final answer
  <({}[({})])>

  # If not 0
  {

    # Pop the difference between the last two numbers
    # Don't include this in the final answer
    (<{}>)

    # Add 1 to the final answer
    ()

  # End if
  }{}

  # Push stack height - 1
  ([][()])

# End while
}

# Switch to the off stack so we don't print anything extra
<>

# Push the total sum. This is the number of times the if was true
)
Райли
источник
1
Поздравляю за 10 тысяч повторений!
Павел
@Pavel Спасибо! Мне потребовалось целую вечность, чтобы получить последние несколько сотен. Я был слишком занят другими вещами :(
Райли
У меня было это
H.PWiz
@ H.PWiz У меня было это в какой-то момент, но мне нравится, как поп отменяет толчок высоты стека.
Райли
5

Haskell , 35 байт

-8 байт благодаря H.PWiz.

Вне игры в гольф по рекурсивной версии . Хаскелл в значительной степени лучший в рекурсии, и я пропустил это. > _ <

f l=sum[1|x<-zipWith(/=)l$tail l,x]

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

Было бы здорово, если бы кто-нибудь понял, как использовать этот совет .

Альтернативное решение, 36 байт

f l=sum[1|True<-zipWith(/=)l$tail l]

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

totallyhuman
источник
1
Также 35
H.PWiz
Этот совет упускает из виду тот факт, что вам нужна uncurryфункция, fчтобы она заработала. Это sum.map fromEnum.(zipWith(/=)=<<tail), вероятно, самое близкое к вам значение, но оно не будет работать []и составляет 37 байт ..
ბიმო
5

Java (OpenJDK 8) , 65 байт

Не так коротко, как хотелось бы, но это просто Java для вас.

Проверьте, передав массив в виде списка через запятую.

a->{int s=0,i=1;for(;i<a.length;s+=a[i-1]!=a[i++]?1:0);return s;}

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

Люк Стивенс
источник
2
Если бы пустой массив не был тестовым примером (и я не считаю его действительно актуальным), можно было бы использовать: a->{int s=0,p=a[0];for(int n:a)s+=p==(p=n)?0:1;return s;}(57 байт).
Оливье Грегуар,
@ Оливье Грегуар, я знаю! Я написал это и подумал, что мне удалось сократить количество байтов, но в первом случае это не удалось.
Люк Стивенс
3
56 байтов:a->{int s=0;for(int i:a)s+=a[0]!=(a[0]=i)?1:0;return s;}
Невай
4

Ом v2 , 3 байта

ΔyΣ

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

объяснение

Δ     absolute differences between consecutive elements
 y    sign: 1 if positive, -1 if negative, 0 if zero
  Σ   sum
Cinaski
источник
Умное использование signвстроенного!
Ник Клиффорд,
@NickClifford Спасибо!
Cinaski
4

Wolfram Language (Mathematica) , 2324 26 29 байтов

Length@Split@#~Max~1-1&

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

  • -1 байт благодаря Мартину Эндеру!
  • -2 байта благодаря JungHwan Min! хорошее использование Split[].
  • -3 байта благодаря полностью человеческому!

небольшое объяснение:

Splitразделит массив на список списков (из одинаковых элементов), то есть превратится {1, 2, 2, 3, 1, 1}в {{1}, {2, 2}, {3}, {1, 1}}. Итак, Length@Split@#количество последовательных сегментов. Max[*****-1, 0]используется для обработки {}ввода.

Кейу Ган
источник
1
26 байтов.
полностью человек
1
24 байта:Max[Length@Split@#-1,0]&
JungHwan Мин
23:Length@Split@#~Max~1-1&
Мартин Эндер
4

Символический Питон , 120 117 байт

Используйте 3 байта, удалив явное приведение к целому (используя унарный +) для переменной счетчика - это означает, что если в массиве нет изменений, вывод будет Falseвместо 0, но это разрешено мета .

___=-~(_==_)
__('___=~-'+`_>_`[___::___]+`__`[-~___]+'(_)')
__('__=___=_>_'+';___+=_[__]!=_[-~__];__=-~__'*___)
_=___

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

# LINE 1: Generate value '2' for utility
___=-~(_==_)

# LINE 2: Get len(input) - 1
__('___=~-'+`_>_`[___::___]+`__`[-~___]+'(_)')
   '___=~-'+`_>_`[___::___]+`__`[-~___]+'(_)'     # Generate string '___=~-len(_)'
            `_>_`[___::___]                       #    'le' spliced from 'False'
                           +`__`[-~___]           #    'n' indexed from '<function ...>'
   '___=~-'+                           +'(_)'     #    Remaining characters in plaintext
__(                                          )    # Execute this to get len(input) - 1

# LINE 3: Main calculation loop
__('__=___=_>_'+';___+=_[__]!=_[-~__];__=-~__'*___) 
__(                                               ) # Execute:
   '__=___=_>_'                                     #   Set var1, var2 to 0
               +';                           '*___  #   len(input) - 1 times do:
                       _[__]!=_[-~__]               #   Compare input[var1, var1 + 1]
                  ___+=              ;              #   Add this to var2
                                      __=-~__       #   Increment var1

# LINE 4: Set output variable ('_') to the result calculated.
_=___                                       
FlipTack
источник
2
= _ = что это за волшебство?
полностью человек
3

Желе , 3 байта

ITL

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

Как это устроено

ITL - Полная программа.

Я - Приращения (дельты).
 T - Получить индексы истинных значений (получает индексы ненулевых элементов).
  L - длина.
Мистер Xcoder
источник
3

K (ок) , 8 байт

Решение:

+/1_~~':

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

Примеры:

+/1_~~':1 1 1 2 2 5 5 5 5 17 3
4
+/1_~~':()
0
+/1_~~':-3 3 3 -3 0
3

Объяснение:

Интерпретируется справа налево:

+/1_~~': / the solution
     ~': / equal each-previous
    ~    / not (ie differ)
  1_     / 1 drop, remove first as this is different to null
+/       / sum up trues
streetster
источник
3

R , 24 байта

cat(sum(!!diff(scan())))

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

То же самое, что и ответ MATL, только что использовался, sum(!!diff))поскольку нет nnz.

Giuseppe
источник
+1 Я думал, что использование rleбудет короче, но нет, length(rle()$v)использует слишком много символов и отключается на один.
Нил Фульц
@NealFultz, вероятно, все еще стоит опубликовать в качестве ответа! Всегда приятно видеть другой подход. И вы должны использовать sum(rle()$v|1)вместо в lengthлюбом случае. :)
Джузеппе
3

Cubix , 24 байта

UpO@0I>I!^-u>q.uvv$!^;)p

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

Обратите внимание, что Cubix использует 0, чтобы указать, что больше нет входов, поэтому 0 не может быть в списке.

объяснение

Развернутая:

    U p
    O @
0 I > I ! ^ - u
> q . u v v $ !
    ^ ;
    ) p

Мы начинаем с 0, помещая счетчик (инициализированный с помощью 0) и первый вход ( I) в стек.

Затем мы входим в петлю. На каждой итерации цикла мы получаем следующий вход с I. Если это 0, у нас закончились входы, поэтому мы вращаем счетчик в top ( p), Output и exit ( @).

В противном случае мы берем разницу двух верхних элементов. Если он ненулевой, мы вращаем счетчик на вершину, увеличиваем его и поворачиваем обратно на дно с помощью p)q. Затем мы выводим разницу, ;прежде чем перейти к следующей итерации.

Все персонажи, не упомянутые здесь, являются просто потоком управления. В программах Cubix их много.


источник
@MickyT Хороший подход, но вы, кажется, переоцениваете на 1. Вы можете поменять местами 0на a (, но это не сработает на пустом вводе.
извиняюсь, посмотрю еще раз
MickyT
3

Brain-Flak , 50 байтов

(([][()]){[{}({}[({})])]{{}()(<()>)}{}([][()])}<>)

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

Так как каждый публикует свои 50-байтовые решения, здесь мое (у меня есть 48- байтовое решение, но это была простая модификация DjMcMayhem, поэтому я чувствовал, что стоит опубликовать)

объяснение

Этот ответ широко использует отмену значения.

Без гольфа это выглядит как

([][()])({<{}({}[({})])>{<{}>()(<()>)}{}<([][()])>}<>)

Здесь мы вычисляем дельту, пока в стеке не останется один элемент, каждый раз, когда мы накапливаем одно значение из внутреннего цикла, если дельта не равна нулю.

Это довольно простой способ сделать это.

Чтобы сделать этот гольф, мы начинаем отмену стоимости. Первый и тот, который должен быть очевиден для любого закаленного игрока в мозги, - это высота стека. Это хорошо известный факт, что

([])({<{}>...<([])>}{})

такой же как

(([]){[{}]...([])}{})

Когда значения изменяются одним, то же самое сохраняется. Это дает нам

(([][()]){[{}]<({}[({})])>{<{}>()(<()>)}{}([][()])}<>)

Вы можете заметить, что это даже не спасло нас от байтов, но не волнуйтесь, это станет более полезным, когда мы продолжим.

Мы можем выполнить другое сокращение, если вы видите заявление

<(...)>{<{}> ...

вы можете уменьшить его до

[(...)]{{} ...

Это работает, потому что если мы войдем в цикл [(...)]и {}отменим, а если нет, то значение [(...)]уже было нулевым, и его не нужно отменять. Поскольку в нашем коде есть этот шаблон, мы можем уменьшить его.

(([][()]){[{}][({}[({})])]{{}()(<()>)}{}([][()])}<>)

Это сэкономило нам 2 байта, но также поставило две точки рядом друг с другом. Они могут быть объединены, чтобы спасти нас еще 2.

(([][()]){[{}({}[({})])]{{}()(<()>)}{}([][()])}<>)

И это наш код.

Мастер пшеницы
источник
3

Perl 6 , 18 байт

{sum $_ Z!= .skip}

Проверь это

Expanded:

{ # bare block lambda with implicit parameter 「$_」

  sum         # count the number of True values

      $_      # the input
    Z!=       # zip using &infix:«!=»
      .skip   # the input, but starting from the second value
              # (implicit method call on 「$_」
}
Брэд Гилберт b2gills
источник
3

Gaia , 2 байта

ėl

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

Это злоупотребляет ошибкой (или особенностью?) Gaia, которая заключается в том, что кодирование длин серий не учитывает последний запуск элементов. Обратите внимание, что я дважды проверил, он работает для всех тестовых случаев.

  • ė - Выполнить кодирование длины (с недостатком, описанным выше).
  • l - длина
Мистер Xcoder
источник
2

JavaScript (ES6), 35 байт

a=>a.filter((e,i)=>e-a[i+1]).length
Нил
источник
Интересно, можно ли его сократить с помощью рекурсии? Но моя лучшая попытка - также 35:f=([a,...b])=>1/a?!!(a-b[0])+f(b):0
Арно
@Arnauld Я тоже это попробовал, но не учел и подумал, что это 36 байтов, иначе я бы добавил его в качестве альтернативы.
Нил
2

APL (Дьялог) , 8 байт

+/2≠/⊃,⊢

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

Как?

⊃,⊢ - список с первым значением, повторенным для случая одного элемента

2≠/ - список изменений, не равный для каждых 2 элементов

+/ - сумма

Уриэль
источник
2

J, 10 байт

[:+/2~:/\]

Инфиксы длины 2 ... они неравны? 2 ~:/\ ]

Подведите итоговый список 0 s и 1s:+/

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

Ион
источник
[:+/0=-/\ должно работать, я думаю, 9 байтов.
Коул
2

Рубин , 31 байт

->a{a.chunk{|x|x}.drop(1).size}

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

Иордания
источник
Вместо .drop(1)тебя можно сделать[1..-1]
Cyoce
@Cyoce К сожалению dropвозвращает Enumerator, а не Array, так что это не работает.
Джордан
да. Возвращает массив на моей версии.
Cyoce
@Cyoce Какая версия?
Джордан
Я на 1.9.3, но почему ты не можешь взять sizeArray?
Cyoce
2

C (gcc 5.4.0), 61 байт

f(c,v)int*v;{int*p=v,s=0;for(;p<v+c-1;s+=*p++!=*p);return s;}

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

f является функцией, принимающей длину массива и указатель на первый элемент массива, и возвращающей количество изменений в массиве;

Это представление использует неопределенное поведение (*p++!=*p p используется дважды в выражении, в котором оно было изменено), которое работает на моем компьютере (gcc 5.4.0) и на TIO, но может не работать на других реализациях или версиях.

Объяснение:

f(c,v)int*v;{ // old-style declaration for v, and implicit-int for c and return value
    int*p=v,s=0; // p is a pointer to the current item, s is the number of changes
    for(;p<v+c-1;s+=*p++!=*p); // for each consecutive pair of integers, if they are different, add one to the number of changes
    return s; // return the number of changes
}
Пиццапанцы184
источник
Не могли бы вы добавить ссылку на среду онлайн-тестирования?
Джонатан Фрех
@JonathanFrech Добавлено
pizzapants184
2

05AB1E , 3 байта

γ¦g

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

Альтернатива ответу Эрика.

γ¦g ~ Полная программа.

γ ~ Сгруппировать в серии равных соседних элементов.
 Remove ~ Удалить первую группу (если есть).
  г ~ длина.
Мистер Xcoder
источник
Ах, пропустил, что это был случай.
Волшебная Осьминог Урна