Нахождение локальных крайностей

14

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

В списке [x_0, x_1, x_2...]локальный экстрим есть x_iтакой, что x_(i-1) < x_iи x_(i+1) < x_iили x_(i-1) > x_iи и x_(i+1) > x_i. Обратите внимание, что первый и последний элементы списка никогда не могут быть локальными крайностями.

Так что для некоторых примеров

local_extremes([1, 2, 1]) = [2]
local_extremes([0, 1, 0, 1, 0]) = [1, 0, 1]
local_extremems([]) = []

Это кодовый гольф, поэтому выигрывает самый короткий код!

Даниэль Гратцер
источник
Чтобы я правильно понял: цифры больше, чем цифры с обеих сторон?
подземный
@undergroundmonorail Больше или меньше чем. Так что это должен быть либо локальный минимум, где его соседи оба больше, либо максимум, где они оба меньше
Даниэль Гратцер
А ну понятно. Я неправильно понял
подземный
2
и что относительно последовательности, 1 2 2 1не должны ли они 2также рассматриваться как крайности? - Я знаю, это сделало бы решение намного сложнее ...
VX

Ответы:

5

Mathematica 66 58 51

Текущее решение

Сокращен благодаря вкладу Калле.

Cases[Partition[#,3,1],{a_,b_,c_}/;(a-b) (b-c)<0⧴b]&

Partition[#,3,1] находит тройки.

(a-b) (b-c)<0истинно , если и только если bниже a, cили выше a, c. и смотрит на признаки различия. Локальный экстрим вернется либо либо, {-1,1}либо {1,-1}.


Примеры

Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{1, 2, 1}]
Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{0, 1, 0, 1, 0}]
Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{}]
Cases[Partition[#, 3, 1], {a_, b_, c_} /; (a - b) (b - c) < 0 :> b] &[{9, 10, 7, 6, 9, 0, 3, 3, 1, 10}]

{2}
{1, 0, 1}
{}
{10, 6, 9, 0, 1}


Предыдущее решение

Это приводит примеры всех троек (сгенерированных Partition) и определяет, является ли средний элемент меньшим, чем оба крайних значения, или большим, чем крайние значения.

Cases[Partition[#,3,1],{a_,b_,c_}/;(b<ab<c)∨(b>ab>c)⧴b]& ;

Первое решение

Это находит тройки и смотрит на признаки различия. Локальный экстрим вернется либо либо, {-1,1}либо {1,-1}.

Cases[Partition[#,3,1],x_/;Sort@Sign@Differences@x=={-1,1}⧴x[[2]]]&

пример

Cases[Partition[#,3,1],x_/;Sort@Sign@Differences@x=={-1,1}:>x[[2]]]&[{9, 10, 7, 6, 9, 0, 3, 3, 1, 10}]

{10, 6, 9, 0, 1}


Анализ :

Partition[{9, 10, 7, 6, 9, 0, 3, 3, 1, 10}]

{{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, { 3, 3, 1}, {3, 1, 10}}

% относится к результату из соответствующей предыдущей строки.

Differences/@ %

{{1, -3}, {-3, -1}, {-1, 3}, {3, -9}, {-9, 3}, {3, 0}, {0, -2}, {-2, 9}}

Sort@Sign@Differences@x=={-1,1}идентифицирует тройки из {{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, {3, 3, 1}, {3, 1, 10}}, так что знак (-, 0, +) разностей состоит из a -1и a 1. В данном случае это:

{{9, 10, 7}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {3, 1, 10}}

Для каждого из этих случаев х, x[[2]] относится ко второму члену. Это будут все локальные максимумы и минимумы.

{10, 6, 9, 0, 1}

DavidC
источник
Ваш стиль Mathematica гораздо более лаконичен, чем мой. Когда мы начнем называть это "Wolfram Language"?
Майкл Стерн
Я вижу это ! Mathematica graphics
Доктор Велизарий
Майкл Стерн, я подозреваю, что Wolfram Language станет официальным только в версии 10, некоторая форма которой уже доступна на Raspberry Pi.
DavidC
Кстати, кто-то вставил строку кода, которая преобразует Math ML в графику. Я не уверен почему.
DavidC
Я не уверен, почему он это сделал. Я не вижу различий в «модифицированном» коде
доктор Белизарий
6

J - 19 символов

Ничего не мог поделать;)

(}:#~0,0>2*/\2-/\])

Объяснение следует:

  • 2-/\] - Для каждой пары элементов в аргументе (каждый инфикс длиной в 2 элемента) возьмите разницу.
  • 2*/\ - Теперь над каждой парой нового списка возьмите товар.
  • 0> - Проверьте, является ли каждый результат меньше 0. Это происходит только в том случае, если у мультипликаторов были знаковые знаки, т. Е. Не бывает, если они имели одинаковый знак или были равны нулю.
  • 0, - Объявите, что первый элемент не является экстремальным.
  • }: - Отрежьте последний элемент, потому что это тоже не может быть экстремальным.
  • #~ - Используйте истинные значения на правой стороне, чтобы выбрать элементы из списка на левой стороне.

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

   (}:#~0,0>2*/\2-/\]) 1 2 1
2
   (}:#~0,0>2*/\2-/\]) 0 1 0 1 0
1 0 1
   (}:#~0,0>2*/\2-/\]) i.0   NB. i.0 is the empty list (empty result also)

   (}:#~0,0>2*/\2-/\]) 3 4 4 4 2 5
2
algorithmshark
источник
Хм, это может не сработать, если вход имеет, скажем, 3, 4, 4, 4, 4, 5, то есть вы можете получить ноль на шаге «0 =», если 0 добавлен к 0.
Lord Soth
Кроме того, я не знаю об этом языке, но вместо того, чтобы взять signum на первом шаге, вы можете оставить разницу как есть. Затем, на втором шаге, вместо этого умножьте элементы, а на третьем вы можете проверить, является ли продукт отрицательным (это также позволяет избежать этой проблемы 0). Возможно, это может привести к сокращению кода.
Лорд Сот
Хороший улов, и да, это спасает двух персонажей. Обновление.
алгоритмическая
5

Javascript - 62 45 символов

f=a=>a.filter((x,i)=>i&&i<a.length-1&&(a[i-1]-x)*(a[i+1]-x)>0)

редактировать

f=a=>a.filter((x,i)=>(a[i-1]-x)*(a[i+1]-x)>0)
mt0
источник
4

Рубин, 83 70 60 55 49 знаков

f=->a{a.each_cons(3){|x,y,z|p y if(x-y)*(z-y)>0}}

Печатает все локальные крайности в STDOUT.

Использует <=>оператор "космический корабль", который мне очень нравится. (Возвращает 1, если первая вещь больше, чем вторая, -1, если она меньше, и 0, если она равна. Следовательно, если они прибавляют к -2 или 2, это означает, что середина является экстремальной.)

Уже нет, как @daniero указал, что «очевидный» путь на самом деле короче!

Изменился еще раз! Теперь он использует потрясающий алгоритм, найденный в ответе МТ0 (+1 к нему!).

Кроме того, мне нравится, each_consкоторый выбирает каждую nгруппу последовательных элементов в массиве. И трейлинг ifтоже интересный.

В целом, мне просто нравится, как элегантно это выглядит.

Некоторые примеры прогонов:

irb(main):044:0> f[[1,2,1]]
2
=> nil
irb(main):045:0> f[[1,0,1,0,1]]
0
1
0
=> nil
irb(main):046:0> f[[]]
=> nil
irb(main):047:0> f[[1,2,3,4,5,4,3,2,1]]
5
=> nil
irb(main):048:0> f[[1,1,1,1,1]]
=> nil
irb(main):049:0> f[[10,0,999,-45,3,4]]
0
999
-45
=> nil
Дверная ручка
источник
Короче распаковать x в 3 переменные:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero
@daniero Спасибо; Я даже не знал, что ты можешь сделать это! Отредактировано
Doorknob
правда ? : D Кстати, теперь, когда каждый член на 3 символа короче, это в целом дешевле x>y&&y<z||x<y&&y>z(даже если оператор космического корабля очень симпатичный);)
daniero
также ... !((x..z)===y)еще короче, хотя и не такой умный
Не то чтобы Чарльз
@ Чарльз Это не удается, когда x < z.
Дверная ручка
3

C ++ - 208 символов

Самое длинное решение снова:

#include<iostream>
#include<deque>
using namespace std;
int main(){deque<int>v;int i;while(cin){cin>>i;v.push_back(i);}for(i=0;i<v.size()-2;)if(v[++i]>v[i-1]&v[i]>v[i+1]|v[i]<v[i-1]&v[i]<v[i+1])cout<<v[i]<<' ';}

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

Входные данные: 0 1 0 x

Выход: 1


источник
Вы можете использовать dequeвместо, vectorчтобы получить 2 символа.
Morwenn
Кроме того, вместо использования iи jвы можете объявить int i;сразу после сбора и использовать два цикла вместо объявления двух переменных.
Morwenn
Наконец, вы, вероятно, можете избавиться от приращения i++в цикле for и начать выполнение условия, if(v[++i]>[i-1]...чтобы снова получить один символ.
Morwenn
2

Matlab - 45 байт

x=input('');y=diff(x);x(find([0 y].*[y 0]<0))
Лорд сот
источник
2

Python 2,7 - 73 байта

e=lambda l:[l[i]for i in range(1,len(l)-1)if(l[i]-l[i-1])*(l[i]-l[i+1])]

Не слишком впечатляет (посмотрите на каждый элемент списка, кроме первого и последнего, посмотрите, больше он или меньше, чем его соседи). Я в основном только публикую это, потому что не все знают, что вы можете сделать это x<y>zи работать. Я думаю, что это здорово.

Да, x<y>zэто отличная особенность Python, но на самом деле она не оптимальна в этом случае. Спасибо VX за трюк умножения, который мне вообще не приходил в голову. Wrzlprmft напомнил мне, что объявление анонимной функции требует меньше нажатий клавиш, чем def x(y):.

undergroundmonorail
источник
if(l[i]-l[i-1])*(l[i]-l[i+1])>0уменьшит код на 11 символов ...
VX
@wrz Ах, ты прав. Я был сбит с толку тем, что def e(l):\n такое же количество символов, как e=lambda l:и я, но я забыл, что вам не нужно использовать returnключевое слово. Благодарность!
подземный
@vx О, мне это очень нравится. Спасибо :) редактировать: На самом деле вы можете сэкономить больше, чем это! Так (l[i]-l[i-1])*(l[i]-l[i+1])как, 1если l[i]это местная крайность и в 0противном случае, мне не нужно использовать >0. Я могу просто позволить Python интерпретировать это как бул. :)
подземный
@wrz Я не могу понять, как редактировать комментарий, который уже был отредактирован (значок карандаша, кажется, заменяет кнопку редактирования. Это из-за дизайна?). Я просто хотел добавить, что если бы я был умным, я бы понял, что моей однострочной функции вообще не нужно указывать \n в объявлении! Это позволило бы сохранить два символа, но включение по- returnпрежнему делает это не стоит.
подземный
2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]
karakfa
источник
1
это только проверка локального максимума, для минимума нужно добавить || x <min pn
karakfa
x>p&&x>nимеет на одного персонажа меньше, чем x>max p n:-)
yatima2975
пробел после ,тоже не нужен.
karakfa
1
изменения x>p&&x>nв (x>p)==(x>n)локальные минимумы тоже добавляют еще 4 символов.
Каракфа
2

Желе , 8 байт

IṠIỊ¬T‘ị

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

объяснение

IṠIỊ¬T‘ị
I          Differences between adjacent elements {of the input}
 Ṡ         Take the sign of each difference
  I        Differences between adjacent difference signs
   Ị       Mark the elements that are     in the range -1..1 inclusive
    ¬                                 not
     T     Take the indexes of the marked elements
      ‘      with an offset of 1
       ị   Index back into the original list

Элемент является только локальным экстремумом, если его различие с его левым соседом имеет знак, противоположный его разнице с его правым соседом, то есть знаки различий отличаются на 2 или -2. У Jelly есть ряд полезных примитивов для работы с «находить элементы с определенными свойствами» (в частности, мы можем найти элементы с определенными свойствами в одном списке и использовать их для извлечения элементов из другого списка), что означает, что мы можем перевести обратно на более или менее непосредственно исходный список (нам просто нужно сместить на 1, потому что первый и последний элементы исходного списка были потеряны при разнице).

ais523
источник
1

Питон с Numpy - 81 74 67 байт ( 61 54 без importстроки)

import numpy
e=lambda a:a[1:-1][(a[2:]-a[1:-1])*(a[1:-1]-a[:-2])<0]

Входные данные должны быть массивом Numpy.

Wrzlprmft
источник
1

С, 83

x,y,z;main(){y=z=0;while(scanf("%d",&x)){(y-z)*(y-x)>0?printf("%d ",y):1;z=y,y=x;}}
VX
источник
1

awk - 32 символа

{c=b;b=a;a=$0;$0=b}(b-c)*(a-b)<0

Не было никакой надежды обойти язык, такой как J или APL, для краткости, но я все равно решил бросить свою шляпу на ринг. Объяснение:

  • В любой момент времени, a, bи cдержать x_i, x_(i-1)иx_(i-2)
  • b-cи a-bприблизить производную до и послеx_(i-1)
  • Если их произведение отрицательно, то одно отрицательно, а другое положительно, то x_(i-1)есть локальная крайность, поэтому напечатайте
laindir
источник
1

Брахилог , 17 байт

s₃{b≠h.&k≠&{⌉|⌋}}

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

Принимает ввод через входную переменную и генерирует вывод через выходную переменную.

s₃{             }    For a length-3 substring of the input:
  {b                 its last two elements
    ≠                are distinct,
     h               and the first of those elements is
      .              the output variable;
       &k            its first two elements
         ≠           are also distinct;
          &{⌉| }     either its largest element
          &{ |⌋}     or its smallest element
                }    is also the output variable.

Если можно было гарантировать, s₃{{⌉|⌋}.&bh}что последовательности значений отсутствуют, сохраняются четыре байта.

Несвязанная строка
источник
1

Wolfram Language (Mathematica) , 43 42 байта

#~Pick~ArrayFilter[#[[2]]!=Median@#&,#,1]&

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

Я думаю, Nothingэто слишком долго ...

#~Pick~                                  &  (* select elements of the input where, *)
       ArrayFilter[                 ,#,1]   (*  when considering the block of length 1 *)
                                            (*    on either side of that element, *)
                   #[[2]]!=Median@#&        (*  its median is not that element *)
attinat
источник
1

05AB1E , 11 10 байт

¥.±¥Ä2Q0šÏ

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

Объяснение:

¥           # Get the forward differences (deltas) of the (implicit) input-list
            #  i.e. [9,10,7,6,9,0,3,3,1,10] → [1,-3,-1,3,-9,3,0,-2,9]
          # Get the signum of each delta (-1 if neg.; 0 if 0; 1 if pos.)
            #  → [1,-1,-1,1,-1,1,0,-1,1]
   ¥        # Get the forward differences of that list again
            #  → [-2,0,2,-2,2,-1,-1,2]
    Ä       # Convert each integer to its absolute value
            #  → [2,0,2,2,2,1,1,2]
     2Q     # And now check which ones are equal to 2 (1 if truthy; 0 if falsey)
            #  → [1,0,1,1,1,0,0,1]
       0š   # Prepend a 0
            #  → [0,1,0,1,1,1,0,0,1]
         Ï  # And only leave the values in the (implicit) input-list at the truthy indices
            #  → [10,6,9,0,1]
            # (after which the result is output implicitly)
Кевин Круйссен
источник
0

PHP, 116 114 113

function _($a){for(;$a[++$i+1];)if(($b=$a[$i])<($c=$a[$i-1])&$b<($d=$a[$i+1])or$b>$c&$b>$d)$r[]=$a[$i];return$r;}

Пример использования:

print_r(_(array(2, 1, 2, 3, 4, 3, 2, 3, 4)));

Array
(
    [0] => 1
    [1] => 4
    [2] => 2
)
Аурел Белый
источник
0

Haskell, 70C

Гольф версия

e(a:b:c:r)
 |a<b&&b>c||a>b&&b<c=b:s
 |True=s
 where s=e(b:c:r)
e _=[]

Неуправляемая версия

-- if it's possible to get three elements from the list, take this one
extrema (a:b:c:rest)
    | a<b && b>c = b:rec
    | a>b && b<c = b:rec
    | otherwise = rec
    where rec = extrema (b:c:rest)
-- if there are fewer than three elements in the list, there are no extrema
extrema _ = []
danmcardle
источник
0

Javascript: 102 символа

function h(a){for(u=i=[];++i<a.length-1;)if(x=a[i-1],y=a[i],z=a[i+1],(x-y)*(y-z)<0)u.push(y);return u}
Виктор Стафуса
источник
0

APL, 19 байт

{⍵/⍨0,⍨0,0>2×/2-/⍵}

Я преобразовал версию с 20 символами J в APL. Но я добавляю ноль к началу и концу вместо удаления первой и последней цифры. В противном случае это работает так же, как версия J.

формальный параметр омега. Это вход в функцию.

user10639
источник
В то время как мы на это, у меня есть версия K, тоже в 22 символов: {x@1+&0>2_*':-':0 0,x}. 6 из этих символов ( 2_и 0 0,) расходуются на защиту от ошибки длины, если аргумент короче, чем два элемента, поэтому если бы не эта проблема, это было бы 16 ... Действие также немного отличается - мы должны повернуть логический список в список индексов с помощью 1+&и использовать его для индексации xснова - но это короче, а также очень K-Ish вещь, которую нужно сделать.
алгоритмическая
Ваша версия K побьет мою версию APL тогда. Моему коду нужны как минимум два числа.
user10639
0

Python 2 , 59 байт

f=lambda l=0,c=0,*r:r and(c,)*(l<c>r[0]or l>c<r[0])+f(c,*r)

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

Эта функция в основном избегает дорогостоящего процесса индексации, принимая элементы списка в качестве аргументов, а не сам список. Хотя в списке осталось более одного элемента, мы рекурсивно строим список, проверяя максимум на каждом шаге.

ARBO
источник