Alla ricerca di estremi locali


14

Scrivi una funzione o un programma che accetta un elenco e produce un elenco degli estremi locali.

In un elenco [x_0, x_1, x_2...]un estremo locale è x_itale che x_(i-1) < x_ie x_(i+1) < x_io x_(i-1) > x_ie x_(i+1) > x_i. Si noti che il primo e l'ultimo elemento dell'elenco non possono mai essere estremi locali.

Quindi per alcuni esempi

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

Questo è il codice golf, quindi vince il codice più corto!


Per essere sicuro di aver capito bene: numeri maggiori dei numeri su entrambi i lati?
undergroundmonorail,

@undergroundmonorail Maggiore o minore di. Quindi deve essere un minimo locale, dove i suoi vicini sono entrambi più grandi, o un massimo dove entrambi sono più piccoli
Daniel Gratzer,

Oh, capisco. Ho letto male
undergroundmonorail il

2
e che dire della sequenza 1 2 2 1non dovrebbero 2essere considerati anche estremi? - Lo so, questo renderebbe la soluzione molto più difficile ...
VX,

Risposte:


5

Mathematica 66 58 51

Soluzione attuale

Accorciato grazie al contributo di Calle.

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

Partition[#,3,1] trova le triple.

(a-b) (b-c)<0è vero se e solo se bè al di sotto a, co sopra a, c. e guarda prende i segni delle differenze. Un estremo locale restituirà {-1,1}o {1,-1}.


Esempi

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}


Soluzione precedente

Questo sembra esempi di tutte le triple (generate da Partition) e determina se l'elemento centrale è inferiore a entrambi gli estremi o maggiore degli estremi.

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

Prima soluzione

Questo trova le triple e guarda prende i segni delle differenze. Un estremo locale restituirà {-1,1}o {1,-1}.

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

Esempio

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}


Analisi :

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

% si riferisce al risultato della rispettiva riga precedente.

Differences/@ %

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

Sort@Sign@Differences@x=={-1,1}identifica le triple da {{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, {3, 3, 1}, {3, 1, 10}} in modo tale che il segno (-, 0, +) delle differenze sia costituito da a -1e a 1. Nel caso presente questi sono:

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

Per ciascuno di questi casi, x, si x[[2]]riferisce al secondo termine. Saranno tutti i massimi e minimi locali.

{10, 6, 9, 0, 1}


Il tuo stile Mathematica è molto più conciso del mio. Quando iniziamo a chiamarlo "Wolfram Language"?
Michael Stern,


Michael Stern, sospetto che Wolfram Language diventerà ufficiale solo alla versione 10, alcune delle quali già disponibili su Raspberry Pi.
DavidC,

A proposito, qualcuno ha inserito una riga di codice che converte la matematica ML in grafica. Non sono sicuro del perché.
DavidC,

Non sono sicuro del perché lo abbia fatto. Non riesco a vedere alcuna differenza nel codice "modificato"
Dr. belisarius,

6

J - 19 caratteri

Non ho potuto farne a meno;)

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

La spiegazione segue:

  • 2-/\] - Su ciascuna coppia di elementi nell'argomento (ogni infisso lungo di 2 elementi), fai la differenza.
  • 2*/\ - Ora su ogni coppia del nuovo elenco, prendi il prodotto.
  • 0> - Verifica se ogni risultato è inferiore a 0. Questo accade solo se i multiplicandi hanno segni alternati, ovvero non accade se avevano lo stesso segno o entrambi erano zero.
  • 0, - Dichiara che il primo elemento non è un elemento estremo.
  • }: - Taglia l'ultimo elemento, perché neanche quello può essere un estremo.
  • #~ - Utilizzare i valori reali sul lato destro per selezionare gli elementi dall'elenco sul lato sinistro.

Uso:

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

Umm, questo potrebbe non funzionare se l'ingresso è, diciamo, 3, 4, 4, 4, 4, 5, ovvero potresti ottenere uno zero nel passaggio "0 =" se 0 viene aggiunto a 0.
Lord Soth,

Inoltre, non conosco questa lingua, ma, invece di prendere il signum nel primo passo, puoi lasciare la differenza così com'è. Quindi, nel secondo passaggio, moltiplica invece gli elementi e nel terzo puoi verificare se il prodotto è negativo (questo evita anche quel problema 0). Forse questo può comportare un codice più breve.
Lord Soth,

Buona cattura, e sì, questo salva due personaggi. In aggiornamento.
algoritmo

5

Javascript - 62 45 personaggi

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

modificare

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

4

Rubino, 83 70 60 55 49 caratteri

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

Stampa tutti gli estremi locali su STDOUT.

Utilizza l' <=>operatore "astronave", che mi piace molto. (Restituisce 1 se la prima cosa è maggiore della seconda, -1 se è inferiore e 0 se uguale. Pertanto, se si aggiungono a -2 o 2, ciò significa che il centro è un estremo.)

Non più, come ha sottolineato @daniero che il modo "ovvio" è in realtà più breve!

Modificato ancora una volta! Ora utilizza il fantastico algoritmo trovato nella risposta di MT0 (+1 per lui!).

Inoltre, mi piace each_consquale seleziona ciascunon gruppo di elementi consecutivi in ​​un array. E anche il trailing ifè interessante.

Nel complesso, mi piace quanto sia elegante.

Alcune esecuzioni di esempio:

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

È più breve decomprimere x in 3 variabili:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero,

@daniero Grazie; Non sapevo nemmeno che potresti farlo! Modificato
Maniglia della porta

davvero ? : D A proposito, ora che ogni termine è più corto di 3 caratteri, è complessivamente più economico da fare x>y&&y<z||x<y&&y>z(anche se l'operatore dell'astronave è molto carino);)
daniero,

inoltre ... !((x..z)===y)è ancora più breve ma non altrettanto intelligente
Non che Charles

@Charles Che fallisce quando x < z.
Maniglia della porta

3

C ++ - 208 caratteri

Ancora la soluzione più lunga:

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

Per usare, inserisci i tuoi numeri interi, quindi qualsiasi carattere che si arresti in modo anomalo nel flusso di input - tutti i caratteri non numerici dovrebbero funzionare.

Ingresso: 0 1 0 x

Produzione: 1


Puoi usare a dequeinvece di a vectorper guadagnare 2 personaggi.
Morwenn,

Inoltre, invece di utilizzare ie j, è possibile dichiarare int i;subito dopo la raccolta e utilizzare in è i due loop anziché dichiarare due variabili.
Morwenn,

Infine, puoi probabilmente sbarazzarti dell'incremento i++nel tuo ciclo for e iniziare le tue condizioni if(v[++i]>[i-1]...per ottenere di nuovo un personaggio.
Morwenn,

2

Matlab - 45 byte

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

2

Python 2.7 - 73 byte

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

Non troppo impressionante (guarda tutti gli elementi dell'elenco tranne il primo e l'ultimo, vedi se è più grande o più piccolo dei suoi vicini). Per lo più lo sto solo postando perché non tutti sanno che puoi farex<y>z e farlo funzionare. Penso che sia un po 'pulito.

Sì, x<y>zè una caratteristica interessante di Python, ma in questo caso non è ottimale. Grazie a VX per il trucco della moltiplicazione, non mi è mai venuto in mente. Wrzlprmft mi ha ricordato che dichiarare una funzione anonima richiede meno battute di def x(y):.


if(l[i]-l[i-1])*(l[i]-l[i+1])>0ridurrebbe il codice di 11 caratteri ...
VX,

@wrz Ah, hai ragione. Sono stato scartato dal fatto che def e(l):\n è lo stesso numero di caratteri di e=lambda l:, ma ho dimenticato che non è necessario utilizzare la returnparola chiave. Grazie!
undergroundmonorail,

@vx Oh, mi piace molto. Grazie :) modifica: in realtà puoi risparmiare di più! Da(l[i]-l[i-1])*(l[i]-l[i+1]) è 1se l[i]è un estremo locale e 0altrimenti, non ho bisogno di usare >0. Posso solo lasciare che Python lo interpreti come un bool. :)
undergroundmonorail,

@wrz Non riesco a capire come modificare un commento che è già stato modificato (l'icona a forma di matita sembra sostituire il pulsante di modifica. È questo di progettazione?). Volevo solo aggiungere che, se fossi stato intelligente, mi sarei reso conto che la mia funzione a una riga non aveva affatto bisogno \n della dichiarazione! Ciò avrebbe salvato due personaggi, ma l'inclusione di returnancora non ne vale la pena.
undergroundmonorail,

2

Haskell 50

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

1
questo controlla solo il massimo locale, per il minimo bisogno di aggiungere || x <min pn
karakfa

x>p&&x>nha un personaggio in meno di x>max p n:-)
yatima2975

,neanche lo spazio dopo è necessario.
Karakfa,

1
cambia x>p&&x>nanche (x>p)==(x>n)per i minimi locali, aggiunge altri 4 caratteri.
karakfa

2

Gelatina , 8 byte

IṠIỊ¬T‘ị

Provalo online!

Spiegazione

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

Un elemento è solo un estremo locale se la sua differenza con il suo vicino sinistro ha un segno opposto alla sua differenza con il suo vicino destro, cioè i segni delle differenze differiscono di 2 o -2. Jelly ha una serie di primitive utili per trattare "trova elementi con determinate proprietà" (in particolare, possiamo trovare elementi con determinate proprietà in un elenco e usarli per estrarre elementi da un altro elenco), il che significa che possiamo tradurre di nuovo in l'elenco originale più o meno direttamente (dobbiamo solo compensare di 1 perché il primo e l'ultimo elemento dell'elenco originale si sono persi nel prendere le differenze).


1

Python con Numpy - 81 74 67 byte ( 61 54 senza la importriga)

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

L'input deve essere un array Numpy.


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

1

awk - 32 caratteri

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

Nessuna speranza di battere un linguaggio come J o APL per brevità, ma ho pensato comunque di buttare il cappello sul ring. Spiegazione:

  • In qualsiasi momento, a, b, e cstretta x_i, x_(i-1)ex_(i-2)
  • b-ce a-bapprossimare il derivato prima e dopox_(i-1)
  • Se il loro prodotto è negativo, quindi uno è negativo e l'altro è positivo, quindi x_(i-1)è un estremo locale, quindi stampa

1

Brachylog , 17 byte

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

Provalo online!

Accetta l'input tramite la variabile di input e genera l'output tramite la variabile di output.

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.

Se si potesse garantire l'assenza di serie di valori, s₃{{⌉|⌋}.&bh}si risparmierebbero quattro byte.



1

Wolfram Language (Mathematica) , 43 42 byte

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

Provalo online!

Immagino Nothingsia troppo lungo ...

#~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 *)

1

05AB1E , 11 10 byte

¥.±¥Ä2Q0šÏ

Provalo online o verifica alcuni altri casi di test .

Spiegazione:

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

Esempio di utilizzo:

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

Array
(
    [0] => 1
    [1] => 4
    [2] => 2
)

0

Haskell, 70C

Versione golfizzata

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

Versione Ungolfed

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

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 byte

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

Ho convertito la versione J da 20 caratteri in APL. Ma aggiungo uno zero all'inizio e alla fine invece di rimuovere la prima e l'ultima cifra. Altrimenti funziona proprio come la versione J.

- parametro formale omega. Questo è l'input per la funzione.


Mentre noi siamo, Ho una versione K, troppo, in 22 caratteri: {x@1+&0>2_*':-':0 0,x}. 6 di questi personaggi ( 2_e 0 0,) vengono spesi per la protezione da un errore di lunghezza se l'argomento è più corto di due elementi, quindi se non fosse per quel problema sarebbe 16 ... L'azione è anche un po 'diversa - dobbiamo girare il elenco booleano in un elenco di indici con cui 1+&utilizzarlo per indicizzarlo di xnuovo - ma è più breve e anche una cosa molto k-ish da fare.
algoritmo

La tua versione K avrebbe battuto la mia versione APL allora. Il mio codice ha bisogno di almeno due numeri.
user10639,

0

Python 2 , 59 byte

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

Provalo online!

Questa funzione evita principalmente la costosa attività di indicizzazione, prendendo gli elementi dell'elenco come argomenti, anziché l'elenco stesso. Sebbene sia rimasto più di un elemento nell'elenco, costruiamo ricorsivamente l'elenco, verificando il massimo per ogni passaggio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.