Lokale Extreme finden

14

Schreiben Sie eine Funktion oder ein Programm, das eine Liste aufnimmt und eine Liste der lokalen Extreme erstellt.

In einer Liste ist [x_0, x_1, x_2...]ein lokales Extrem ein x_isolches x_(i-1) < x_iund x_(i+1) < x_ioder x_(i-1) > x_iund x_(i+1) > x_i. Beachten Sie, dass das erste und letzte Element der Liste niemals lokale Extreme sein können.

Also für einige Beispiele

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

Dies ist Codegolf, also gewinnt der kürzeste Code!

Daniel Gratzer
quelle
Um sicherzugehen, dass ich richtig verstehe: Zahlen größer als die Zahlen auf beiden Seiten?
Undergroundmonorail
@undergroundmonorail Größer oder kleiner als. Es muss also entweder ein lokales Minimum sein, bei dem beide Nachbarn größer sind, oder ein Maximum, bei dem beide kleiner sind
Daniel Gratzer,
Oh, ich verstehe. Ich habe es falsch verstanden
undergroundmonorail
2
und was ist mit der Sequenz, 1 2 2 1sollten diese nicht 2auch als Extreme betrachtet werden? - Ich weiß, dies würde die Lösung viel schwieriger machen ...
VX

Antworten:

5

Mathematica 66 58 51

Aktuelle Lösung

Verkürzt durch einen Beitrag von Calle.

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

Partition[#,3,1] findet die dreifachen.

(a-b) (b-c)<0wenn wahr ist , und nur dann , wenn bunter a, coder über a, c. und schaut auf nimmt die Anzeichen der Unterschiede. Ein lokales Extrem wird entweder {-1,1}oder zurückkehren {1,-1}.


Beispiele

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}


Frühere Lösung

Dies sieht beispielhaft alle Tripel (generiert von Partition) aus und bestimmt, ob das mittlere Element kleiner als beide Extreme oder größer als die Extreme ist.

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

Erste Lösung

Dies findet die Dreiergruppen und nimmt die Anzeichen der Unterschiede wahr. Ein lokales Extrem wird entweder {-1,1}oder zurückkehren {1,-1}.

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

Beispiel

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}


Analyse :

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

% verweist auf das Ergebnis aus der jeweils vorhergehenden Zeile.

Differences/@ %

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

Sort@Sign@Differences@x=={-1,1}identifiziert die Tripel aus {{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3}. 3}, {3, 3, 1}, {3, 1, 10}}, so dass das Vorzeichen (-, 0, +) der Differenzen aus a -1und a besteht 1. Im vorliegenden Fall sind dies:

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

Für jeden dieser Fälle x[[2]]bezieht sich x auf den zweiten Term. Dies sind alle lokalen Maxima und Minima.

{10, 6, 9, 0, 1}

DavidC
quelle
Ihr Mathematica-Stil ist viel prägnanter als meiner. Wann nennen wir es "Wolfram-Sprache"?
Michael Stern
Ich sehe es ! Mathematica Grafiken
Dr. belisarius
Michael Stern, ich vermute Wolfram Language wird erst ab Version 10 offiziell, von denen eine Form bereits auf Raspberry Pi verfügbar ist.
DavidC
Übrigens hat jemand eine Codezeile eingefügt, die die Math ML in Grafiken konvertiert. Ich bin mir nicht sicher warum.
DavidC
Ich bin mir nicht sicher, warum er es getan hat. Ich kann keine Unterschiede im "geänderten" Code erkennen
Dr. belisarius
6

J - 19 char

Konnte nicht helfen;)

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

Erklärung folgt:

  • 2-/\] - Über jedes Elementpaar im Argument (jedes 2-Item-Long-Infix) den Unterschied ziehen.
  • 2*/\ - Nehmen Sie nun über jedes Paar der neuen Liste das Produkt.
  • 0> - Prüfen Sie, ob jedes Ergebnis kleiner als 0 ist. Dies geschieht nur, wenn die Multiplikanden alternierende Vorzeichen hatten, dh nicht, wenn sie dasselbe Vorzeichen hatten oder eines von beiden Null war.
  • 0, - Deklarieren Sie, dass das erste Element kein extremes Element ist.
  • }: - Schneiden Sie das letzte Element ab, denn das kann auch kein Extrem sein.
  • #~ - Verwenden Sie die wahren Werte auf der rechten Seite, um Elemente aus der Liste auf der linken Seite auszuwählen.

Verwendung:

   (}:#~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
quelle
Ähm, dies funktioniert möglicherweise nicht, wenn die Eingabe beispielsweise 3, 4, 4, 4, 4, 5 lautet, dh wenn 0 zu 0 addiert wird, erhalten Sie im Schritt "0 =" möglicherweise eine Null.
Lord Soth,
Ich kenne diese Sprache auch nicht, aber anstatt das Signum im ersten Schritt zu übernehmen, können Sie den Unterschied so lassen, wie er ist. Dann multiplizieren Sie im zweiten Schritt stattdessen die Elemente und im dritten können Sie prüfen, ob das Produkt negativ ist (dies vermeidet auch das 0-Problem). Möglicherweise führt dies zu einem kürzeren Code.
Lord Soth
Guter Fang, und ja, das spart zwei Zeichen. Aktualisierung.
Algorithmushai
5

Javascript - 62 45 Zeichen

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

Bearbeiten

f=a=>a.filter((x,i)=>(a[i-1]-x)*(a[i+1]-x)>0)
MT0
quelle
4

Ruby, 83 70 60 55 49 Zeichen

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

Gibt alle lokalen Extreme in STDOUT aus.

Benutzt den <=>"Raumschiff" -Operator, den ich wirklich mag. (Es gibt 1 zurück, wenn das erste Ding größer als das zweite ist, -1, wenn es kleiner ist, und 0, wenn es gleich ist. Wenn sie also zu -2 oder 2 addieren, bedeutet das, dass die Mitte ein Extrem ist.)

Nicht mehr, da @daniero darauf hingewiesen hat, dass der "offensichtliche" Weg tatsächlich kürzer ist!

Schon wieder geändert! Jetzt wird der fantastische Algorithmus verwendet, der in MT0s Antwort enthalten ist (+1 für ihn!).

Außerdem gefällt mir, each_conswelche nGruppen von aufeinanderfolgenden Elementen in einem Array ausgewählt werden. Und das Schleppen ifist auch interessant.

Insgesamt gefällt mir, wie elegant es aussieht.

Einige Probeläufe:

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
Türknauf
quelle
Es ist kürzer, x in 3 Variablen zu entpacken:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
Daniero
@daniero Danke; Ich wusste nicht einmal, dass du das kannst! Bearbeitet
Türknauf
wirklich ? : D Übrigens, jetzt, da jeder Begriff 3 Zeichen kürzer ist, ist es insgesamt billiger zu tun x>y&&y<z||x<y&&y>z(auch wenn der Raumschiffbetreiber sehr hübsch ist);)
Daniero
auch ... !((x..z)===y)ist noch kürzer, wenn auch nicht so schlau
Nicht dass Charles
@ Charles Das schlägt fehl, wenn x < z.
Türknauf
3

C ++ - 208 Zeichen

Wieder die längste Lösung:

#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]<<' ';}

Geben Sie zur Verwendung Ihre ganzen Zahlen und dann ein beliebiges Zeichen ein, das den Eingabestream zum Absturz bringt. Alle Zeichen, die keine Zahlen sind, sollten funktionieren.

Eingang: 0 1 0 x

Ausgabe: 1

Hosch250
quelle
Sie können a dequeanstelle von a verwenden vector, um 2 Zeichen zu erhalten.
Morwenn
Anstatt iund zu verwenden j, können Sie auch int i;direkt nach der Sammlung deklarieren und in den beiden Schleifen verwenden, anstatt zwei Variablen zu deklarieren.
Morwenn
Schließlich können Sie wahrscheinlich das Inkrement i++in Ihrer for-Schleife loswerden und Ihre Bedingung mit beginnen if(v[++i]>[i-1]..., um wieder ein Zeichen zu erhalten.
Morwenn
2

Matlab - 45 Bytes

x=input('');y=diff(x);x(find([0 y].*[y 0]<0))
Lord Soth
quelle
2

Python 2.7 - 73 Bytes

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

Nicht zu beeindruckend (Sehen Sie sich jedes Element der Liste mit Ausnahme des ersten und des letzten an, um festzustellen, ob es größer oder kleiner als die Nachbarn ist). Ich poste es meistens nur, weil nicht jeder weiß, dass Sie es tun x<y>zund funktionieren lassen können. Ich finde das irgendwie ordentlich.

Ja, x<y>zist eine coole Funktion von Python, aber in diesem Fall nicht optimal. Vielen Dank an VX für den Multiplikationstrick, der mir überhaupt nicht eingefallen ist. Wrzlprmft erinnerte mich daran, dass das Deklarieren einer anonymen Funktion weniger Tastenanschläge als ist def x(y):.

untergrundbahn
quelle
if(l[i]-l[i-1])*(l[i]-l[i+1])>0 würde den Code um 11 Zeichen reduzieren ...
VX
@wrz Ah, du hast recht. Ich war durch die Tatsache, dass def e(l):\n die gleiche Anzahl von Zeichen wie e=lambda l:, aber ich habe vergessen, dass Sie das returnSchlüsselwort nicht verwenden müssen, verblüfft. Vielen Dank!
Undergroundmonorail
@vx Oh, das gefällt mir sehr gut. Danke :) edit: Eigentlich kannst du mehr als das sparen! Da (l[i]-l[i-1])*(l[i]-l[i+1])ist , 1wenn l[i]ein lokales Extrem ist und 0sonst brauche ich nicht zu verwenden >0. Ich kann Python einfach als Bool interpretieren lassen. :)
undergroundmonorail
@wrz Ich kann nicht herausfinden, wie ein bereits bearbeiteter Kommentar bearbeitet wird (das Stiftsymbol scheint die Schaltfläche zum Bearbeiten zu ersetzen. Ist dies beabsichtigt?). Ich wollte nur hinzufügen, dass ich, wenn ich schlau wäre, gemerkt hätte, dass meine Einzeilenfunktion das \n in der Deklaration überhaupt nicht benötigt ! Das hätte zwei Zeichen gespart, aber die Einbeziehung von returnmacht es immer noch nicht wert.
Undergroundmonorail
2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]
Karakfa
quelle
1
Dies überprüft nur das lokale Maximum, für das mindestens || hinzugefügt werden muss x <min pn
Karakfa
x>p&&x>nhat einen Charakter weniger als x>max p n:-)
Yatima2975
ein Leerzeichen danach ,ist ebenfalls nicht erforderlich.
Karakfa
1
Wechsel x>p&&x>nan (x>p)==(x>n)für lokale Minima zu fügt 4 weitere Zeichen.
Karakfa
2

Gelee , 8 Bytes

IṠIỊ¬T‘ị

Probieren Sie es online!

Erläuterung

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

Ein Element ist nur dann ein lokales Extrem, wenn sein Unterschied zum linken Nachbarn ein entgegengesetztes Vorzeichen zu seinem Unterschied zum rechten Nachbarn hat, dh die Vorzeichen der Unterschiede unterscheiden sich um 2 oder -2. Jelly hat eine Reihe nützlicher Grundelemente für den Umgang mit "Elementen mit bestimmten Eigenschaften suchen" (insbesondere können wir Elemente mit bestimmten Eigenschaften in einer Liste suchen und diese verwenden, um Elemente aus einer anderen Liste zu extrahieren), was bedeutet, dass wir zurückübersetzen können die ursprüngliche Liste mehr oder weniger direkt (wir müssen nur um 1 versetzen, weil das erste und das letzte Element der ursprünglichen Liste bei der Differenzbildung verloren gegangen sind).

ais523
quelle
1

Python mit Numpy - 81 74 67 Bytes ( 61 54 ohne die importLinie)

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

Die Eingabe muss ein Numpy-Array sein.

Wrzlprmft
quelle
1

C 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
quelle
1

awk - 32 Zeichen

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

Keine Hoffnung, eine Sprache wie J oder APL wegen der Kürze zu schlagen, aber ich dachte, ich würde trotzdem meinen Hut in den Ring werfen. Erläuterung:

  • Zu jedem gegebenen Zeitpunkt, a, b, und chält x_i, x_(i-1)undx_(i-2)
  • b-cund a-bapproximiere die Ableitung davor und danachx_(i-1)
  • Wenn ihr Produkt negativ ist, ist eines negativ und das andere positiv, daher x_(i-1)handelt es sich um ein lokales Extrem, also drucken Sie
Laindir
quelle
1

Brachylog , 17 Bytes

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

Probieren Sie es online!

Übernimmt die Eingabe über die Eingabevariable und generiert die Ausgabe über die Ausgabevariable.

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.

Wenn garantiert werden kann, dass Werteläufe fehlen, werden s₃{{⌉|⌋}.&bh}vier Bytes eingespart.

Nicht verwandte Zeichenfolge
quelle
1

Wolfram Language (Mathematica) , 43 42 Bytes

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

Probieren Sie es online!

Ich denke, Nothingist zu lang ...

#~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
quelle
1

05AB1E , 11 10 Bytes

¥.±¥Ä2Q0šÏ

Probieren Sie es online aus oder überprüfen Sie ein paar weitere Testfälle .

Erläuterung:

¥           # 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)
Kevin Cruijssen
quelle
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;}

Anwendungsbeispiel:

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

Array
(
    [0] => 1
    [1] => 4
    [2] => 2
)
Aurel Bílý
quelle
0

Haskell, 70 ° C

Golf 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 _ = []
danmcardle
quelle
0

Javascript: 102 Zeichen

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}
Victor Stafusa
quelle
0

APL, 19 Bytes

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

Ich habe die 20-Zeichen-J-Version in APL konvertiert. Aber ich füge am Anfang und am Ende eine Null hinzu, anstatt die erste und die letzte Ziffer zu entfernen. Ansonsten funktioniert es genauso wie die J-Version.

- Formalparameter Omega. Dies ist die Eingabe für die Funktion.

user10639
quelle
Während wir gerade dabei sind, habe ich eine K - Version haben, auch in 22 Zeichen: {x@1+&0>2_*':-':0 0,x}. 6 dieser Zeichen ( 2_und 0 0,) werden zum Schutz vor einem Längenfehler ausgegeben, wenn das Argument kürzer als zwei Elemente ist. Wäre dies nicht der Fall, wären es 16 ... Die Aktion ist auch etwas anders - wir müssen die drehen Boolesche Liste in eine Liste von Indizes mit 1+&und verwenden Sie diese, um xerneut zu indizieren - aber es ist kürzer und auch eine sehr k-ische Sache, die zu tun ist.
Algorithmushai
Ihre K-Version würde dann meine APL-Version schlagen. Mein Code benötigt mindestens zwei Zahlen.
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)

Probieren Sie es online!

Diese Funktion vermeidet meist das teure Indizieren, indem die Elemente der Liste anstelle der Liste selbst als Argumente verwendet werden. Während die Liste mehr als ein Element enthält, wird die Liste rekursiv aufgebaut und bei jedem Schritt auf ein Maximum geprüft.

ArBo
quelle