Пошук локальних крайнощів


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 Більше або менше. Тож або повинен бути локальний мінімум, де сусідів і більше, або максимум там, де вони обидва менші
Даніель Гратцер,

О Я бачу. Я неправильно його прочитав
undergroundmonorail

2
а що з послідовністю, 1 2 2 1чи не слід також 2їх вважати крайнощами? - Я знаю, це ускладнить рішення набагато складніше ...
VX

Відповіді:


5

Математика 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}


Ваш математичний стиль набагато більш стислий, ніж мій. Коли ми почнемо називати його «Вольфрамською мовою»?
Майкл Стерн


Майкл Стерн, я підозрюю, що мова Wolfram стане офіційною лише у версії 10, яка форма вже доступна на Raspberry Pi.
DavidC

До речі, хтось вставив рядок коду, який перетворює Math ML у графіку. Я не впевнений, чому.
DavidC

Я не впевнений, чому він це зробив. Я не бачу різниць у "модифікованому" коді
д-р belisarius,

6

J - 19 char

Не могло це допомогти;)

(}:#~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

Гм, це може не спрацювати, якщо вхід, скажімо, 3, 4, 4, 4, 4, 5, тобто ви можете отримати нуль на кроці "0 =", якщо 0 додати до 0.
Лорд Сот,

Також я не знаю про цю мову, але, замість того, щоб взяти симптом на першому кроці, ви можете залишити різницю такою, якою є. Потім на другому кроці замість цього помножте елементи, а на третьому ви можете перевірити, чи добуток від’ємний (це також дозволяє уникнути 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)

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 вказував, що "очевидний" шлях насправді коротший!

Змінено ще раз! Тепер він використовує дивовижний алгоритм, знайдений у відповіді MT0 (+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 Btw, тепер, коли кожен термін на 3 символи коротший, це робити в цілому дешевше x>y&&y<z||x<y&&y>z(навіть оператор космічного корабля дуже симпатичний);)
daniero

також ... !((x..z)===y)ще коротше, але не настільки розумне
Не те, що Чарльз

@Charles Виходить з ладу, коли 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 символи.
Морвен

Крім того, замість використання iта j, ви можете оголосити int i;відразу після збирання та використання в ньому двох циклів замість оголошення двох змінних.
Морвен

Нарешті, ви, ймовірно, можете позбутися приросту i++у вашому циклі та почати свій стан, if(v[++i]>[i-1]...щоб знову набрати один символ.
Морвен


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це класна особливість пітона, але насправді це не є оптимальним в цьому випадку. Завдяки VX за трюк множення, який у мене взагалі не траплявся. Wrzlprmft нагадав мені, що оголошення анонімної функції менше натискань клавіш, ніж def x(y):.


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 інтерпретувати це як бул. :)
undergroundmonorail

@wrz Я не можу зрозуміти, як відредагувати коментар, який уже відредагований (здається, що піктограма олівця замінює кнопку редагування. Це за дизайном?). Я просто хотів додати, що якби я був розумним, я зрозумів би, що моя однолінійна функція зовсім не потрібна \n в декларації! Це врятувало б двох символів, але включення returnвсе ж робить це не варто.
підземниймонорельс

2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]

1
це лише перевірка локального максимуму, для мінімуму потрібно додати || x <min pn
karakfa

x>p&&x>nмає на одного персонажа менше, ніж x>max p n:-)
yatima2975

простір після ,також не потрібен.
карафафа

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, тому що перший і останній елементи оригінального списку загубилися при прийнятті різниць).


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.


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;}}

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)тому це місцевий крайній край, тому друкуйте

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

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

Golfed version

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

Ungolfed version

-- 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 _ = []

0

Javascript: 102 characters

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 bytes

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

I converted the 20 char J version to APL. But I add a zero to the beginning and the end instead of removing the first and last digit. Otherwise it works just like the J version.

- formal parameter omega. This is the input to the function.


While we're at it, I have a K version, too, in 22 characters: {x@1+&0>2_*':-':0 0,x}. 6 of these characters (2_ and 0 0,) are spent protecting against a length error if the argument is shorter than two items, so if not for that problem it would be 16... The action is also a little different--we have to turn the boolean list into a list of indices with 1+& and use that to index x again--but it's shorter and also a very K-ish thing to do.
algorithmshark

Your K version would beat my APL version then. My code needs at least two numbers.
user10639

0

Python 2, 59 bytes

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

Try it online!

This function mostly avoids the costly business of indexing, by taking the elements of the list as arguments, instead of the list itself. While there is more than one element left in the list, we recursively build up the list, checking for a maximum at each step.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.