Encontrar extremos locales

14

Escriba una función o programa que tome una lista y produzca una lista de los extremos locales.

En una lista, [x_0, x_1, x_2...]un extremo local es x_ital que x_(i-1) < x_iy x_(i+1) < x_io x_(i-1) > x_iy x_(i+1) > x_i. Tenga en cuenta que el primer y el último elemento de la lista nunca pueden ser extremos locales.

Entonces, para algunos ejemplos

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

Este es el código de golf, por lo que gana el código más corto.

Daniel Gratzer
fuente
Para asegurarme de que entiendo correctamente: ¿Números mayores que los números de cada lado?
undergroundmonorail
@undergroundmonorail Mayor o menor que. Por lo tanto, debe ser un mínimo local, donde sus vecinos son mayores o un máximo donde ambos son más pequeños
Daniel Gratzer, del
Oh ya veo. Lo leí mal
undergroundmonorail
2
¿Y qué hay de la secuencia? 1 2 2 1¿No deberían 2considerarse también los extremos? - Lo sé, esto haría la solución mucho más difícil ...
VX

Respuestas:

5

Mathematica 66 58 51

Solución actual

Acortado gracias a una contribución de Calle.

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

Partition[#,3,1] encuentra los triples

(a-b) (b-c)<0es verdadero si y sólo si bestá por debajo a, co por encima a, c. y mira toma los signos de las diferencias. Un extremo local volverá {-1,1}o {1,-1}.


Ejemplos

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}


Solución anterior

Esto busca ejemplos de todos los triples (generados por Partition) y determina si el elemento del medio es menor que ambos extremos o mayor que los extremos.

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

Primera solución

Esto encuentra los triples, y observa los signos de las diferencias. Un extremo local volverá {-1,1}o {1,-1}.

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

Ejemplo

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}


Análisis :

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

% se refiere al resultado de la respectiva línea anterior.

Differences/@ %

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

Sort@Sign@Differences@x=={-1,1}identifica los triples de {{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, {3, 3, 1}, {3, 1, 10}} de modo que el signo (-, 0, +) de las diferencias consiste en ay -1a 1. En el presente caso esos son:

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

Para cada uno de estos casos, x, se x[[2]]refiere al segundo término. Esos serán todos los máximos y mínimos locales.

{10, 6, 9, 0, 1}

DavidC
fuente
Su estilo de Mathematica es mucho más conciso que el mío. ¿Cuándo empezamos a llamarlo "Wolfram Language"?
Michael Stern
Veo esto ! Gráficos de Mathematica
Dr. belisarius
Michael Stern, sospecho que Wolfram Language solo se hará oficial en la versión 10, alguna forma de la cual ya está disponible en Raspberry Pi.
DavidC
Por cierto, alguien insertó una línea de código que convierte Math ML a gráficos. No estoy seguro de por qué.
DavidC
No estoy seguro de por qué lo hizo. No puedo ver ninguna diferencia en el código "modificado"
Dr. belisarius
6

J - 19 char

No pude evitarlo;)

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

La explicación sigue:

  • 2-/\] - Sobre cada par de elementos en el argumento (cada infijo largo de 2 elementos), tome la diferencia.
  • 2*/\ - Ahora sobre cada par de la nueva lista, tome el producto.
  • 0> - Pruebe si cada resultado es menor que 0. Esto solo sucede si los multiplicandos tenían signos alternos, es decir, no sucede si tenían el mismo signo o si era cero.
  • 0, - Declarar que el primer elemento no es un elemento extremo.
  • }: - Corta el último elemento, porque eso tampoco puede ser un extremo.
  • #~ - Utilice los valores verdaderos en el lado derecho para elegir elementos de la lista en el lado izquierdo.

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
Algoritmo de tiburón
fuente
Umm, esto puede no funcionar si la entrada es, digamos, 3, 4, 4, 4, 4, 5, es decir, puede obtener un cero en el paso "0 =" si se agrega 0 a 0.
Lord Soth
Además, no sé acerca de este idioma, pero, en lugar de tomar el signum en el primer paso, puede dejar la diferencia como está. Luego, en el segundo paso, multiplique los elementos en su lugar, y en el tercero puede verificar si el producto es negativo (esto también evita ese problema 0). Quizás esto puede resultar en un código más corto.
Lord Soth
Buena captura, y sí, esto salva dos personajes. Actualizando
algorithmshark
5

Javascript - 62 45 caracteres

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

Editar

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

Ruby, 83 70 60 55 49 caracteres

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

Imprime todos los extremos locales en STDOUT.

Utiliza el <=>operador de "nave espacial", que realmente me gusta. (Devuelve 1 si lo primero es mayor que lo segundo, -1 si es menor y 0 si es igual. Por lo tanto, si suman a -2 o 2, eso significa que el medio es un extremo).

¡Ya no más, como @daniero señaló que la forma "obvia" es en realidad más corta!

Cambiado una vez más! Ahora usa el asombroso algoritmo que se encuentra en la respuesta de MT0 (¡+1 para él!).

Además, me gusta each_consque selecciona cada ngrupo de elementos consecutivos en una matriz. Y seguir también ifes interesante.

En general, me gusta lo elegante que se ve.

Algunas ejecuciones de muestra:

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
Pomo de la puerta
fuente
Es más corto descomprimir x en 3 variables:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero
@daniero Gracias; ¡Ni siquiera sabía que podías hacer eso! Editado
Pomo de la puerta
Realmente ? : D Btw, ahora que cada término es 3 caracteres más corto, en general es más barato hacerlo x>y&&y<z||x<y&&y>z(incluso si el operador de la nave espacial es muy bonito);)
daniero
también ... !((x..z)===y)es aún más corto, aunque no tan inteligente
No es que Charles
@ Charles Eso falla cuando x < z.
Pomo de la puerta
3

C ++ - 208 caracteres

La solución más larga nuevamente:

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

Para usar, ingrese sus enteros, luego cualquier carácter que bloqueará la secuencia de entrada; cualquier carácter que no sea un número debería funcionar.

Entrada: 0 1 0 x

Salida: 1


fuente
Puede usar a en dequelugar de a vectorpara obtener 2 caracteres.
Morwenn
Además, en lugar de usar iy j, puede declarar int i;justo después de la colección y usar los dos bucles en lugar de declarar dos variables.
Morwenn
Finalmente, probablemente puedas deshacerte del incremento i++en tu ciclo for y comenzar tu condición if(v[++i]>[i-1]...para volver a obtener un personaje.
Morwenn
2

Matlab - 45 bytes

x=input('');y=diff(x);x(find([0 y].*[y 0]<0))
Señor Soth
fuente
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])]

No es demasiado impresionante (Mire cada elemento de la lista, excepto el primero y el último, vea si es más grande o más pequeño que sus vecinos). Principalmente solo lo publico porque no todos saben que puedes hacerx<y>z y que funcione. Creo que es un poco ordenado.

Sí, x<y>zes una característica genial de Python, pero en realidad no es óptima en este caso. Gracias a VX por el truco de la multiplicación, eso no se me ocurrió en absoluto. Wrzlprmft me recordó que declarar una función anónima es menos pulsaciones de teclas que def x(y):.

metro subterráneo
fuente
if(l[i]-l[i-1])*(l[i]-l[i+1])>0reduciría el código en 11 caracteres ...
VX
@wrz Ah, tienes razón. Me sorprendió el hecho de que def e(l):\n tiene la misma cantidad de caracteres que e=lambda l:, pero olvidé que no es necesario usar la returnpalabra clave. ¡Gracias!
undergroundmonorail
@vx Oh, eso me gusta mucho. Gracias :) editar: ¡ En realidad puedes ahorrar más que eso! Como (l[i]-l[i-1])*(l[i]-l[i+1])es 1si l[i]es un extremo local y de lo 0contrario, no necesito usar >0. Solo puedo dejar que Python lo interprete como un bool. :)
undergroundmonorail
@wrz No puedo entender cómo editar un comentario que ya ha sido editado (el ícono del lápiz parece reemplazar el botón de edición. ¿Es esto por diseño?). ¡Solo quería agregar que, si fuera inteligente, me habría dado cuenta de que mi función de una línea no necesitaba \n la declaración en absoluto! Eso habría salvado a dos personajes, pero la inclusión de returntodavía hace que no valga la pena.
undergroundmonorail
2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]
karakfa
fuente
1
esto solo verifica el máximo local, para mínimo necesita agregar || x <min pn
karakfa
x>p&&x>ntiene un carácter menos que x>max p n:-)
yatima2975
espacio después ,tampoco es necesario.
karakfa
1
cambiar x>p&&x>na (x>p)==(x>n)mínimos locales también, agrega 4 caracteres más.
karakfa
2

Jalea , 8 bytes

IṠIỊ¬T‘ị

Pruébalo en línea!

Explicación

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 es solo un extremo local si su diferencia con su vecino izquierdo tiene un signo opuesto a su diferencia con su vecino derecho, es decir, los signos de las diferencias difieren en 2 o -2. Jelly tiene una serie de primitivas útiles para tratar "buscar elementos con ciertas propiedades" (en particular, podemos encontrar elementos con ciertas propiedades en una lista y usarlos para extraer elementos de una lista diferente), lo que significa que podemos traducir de nuevo a la lista original más o menos directamente (solo necesitamos compensar por 1 porque el primer y el último elemento de la lista original se perdieron en la toma de diferencias).

ais523
fuente
1

Python con Numpy - 81 74 67 bytes ( 61 54 sin la importlínea)

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

La entrada debe ser una matriz Numpy.

Wrzlprmft
fuente
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
fuente
1

awk - 32 caracteres

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

No tengo esperanzas de superar un lenguaje como J o APL por brevedad, pero pensé en tirar mi sombrero al ring de todos modos. Explicación:

  • En un momento dado, a, b, y cespera x_i, x_(i-1)yx_(i-2)
  • b-cy a-baproximar la derivada antes y despuésx_(i-1)
  • Si su producto es negativo, entonces uno es negativo y el otro es positivo, por lo tanto, x_(i-1)es un extremo local, así que imprima
laindir
fuente
1

Brachylog , 17 bytes

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

Pruébalo en línea!

Toma la entrada a través de la variable de entrada y genera la salida a través de la variable de salida.

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.

Si se pudiera garantizar la ausencia de ejecuciones de valores, s₃{{⌉|⌋}.&bh}se ahorrarían cuatro bytes.

Cadena no relacionada
fuente
1

Wolfram Language (Mathematica) , 43 42 bytes

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

Pruébalo en línea!

Supongo que Nothinges demasiado largo ...

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

05AB1E , 11 10 bytes

¥.±¥Ä2Q0šÏ

Pruébelo en línea o verifique algunos casos de prueba más .

Explicación:

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

Ejemplo de uso:

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

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

Haskell, 70C

Versión de golf

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

Versión sin golf

-- 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
fuente
0

Javascript: 102 caracteres

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
fuente
0

APL, 19 bytes

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

Convertí la versión de 20 char J a APL. Pero agrego un cero al principio y al final en lugar de eliminar el primer y último dígito. De lo contrario, funciona igual que la versión J.

- parámetro formal omega. Esta es la entrada a la función.

usuario10639
fuente
Mientras estamos en ello, tengo una versión K, también, en 22 caracteres: {x@1+&0>2_*':-':0 0,x}. 6 de estos caracteres ( 2_y 0 0,) se gastan protegiendo contra un error de longitud si el argumento es más corto que dos elementos, por lo que si no fuera por ese problema serían 16 ... La acción también es un poco diferente: tenemos que cambiar el lista booleana en una lista de índices con 1+&y úsela para indexar xnuevamente, pero es más corta y también es algo muy K-ish.
algorithmshark
Su versión K superaría mi versión APL entonces. Mi código necesita al menos dos números.
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)

Pruébalo en línea!

Esta función evita principalmente el costoso negocio de la indexación, tomando los elementos de la lista como argumentos, en lugar de la lista misma. Si bien queda más de un elemento en la lista, acumulamos recursivamente la lista, verificando un máximo en cada paso.

ArBo
fuente