Encontrando Extremos Locais


14

Escreva uma função ou programa que inclua uma lista e produza uma lista dos extremos locais.

Em uma lista, [x_0, x_1, x_2...]um extremo local é x_ital que x_(i-1) < x_ie x_(i+1) < x_iou x_(i-1) > x_ie x_(i+1) > x_i. Observe que o primeiro e o último elementos da lista nunca podem ser extremos locais.

Então, para alguns exemplos

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

Este é um código de golfe, então o código mais curto vence!


Para ter certeza de que entendi corretamente: Números maiores que os números de ambos os lados?
Undergroundmonorail

@undergroundmonorail Maior ou menor que. Por isso, ou tem que ser um mínimo local, onde é vizinhos são ambos maiores, ou um máximo onde ambos são menores
Daniel Gratzer

Ah eu vejo. Eu li errado
undergroundmonorail

2
e quanto à sequência, 1 2 2 1também não deveriam 2ser considerados extremos? - Eu sei, isso tornaria a solução muito mais difícil ...
VX

Respostas:


5

Mathematica 66 58 51

Solução Atual

Encurtado graças a uma contribuição da Calle.

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

Partition[#,3,1] encontra os triplos.

(a-b) (b-c)<0é verdadeira se e somente se bestiver abaixo a, cou acima a, c. e olha leva os sinais das diferenças. Um extremo local retornará um {-1,1}ou {1,-1}.


Exemplos

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}


Solução anterior

Este exemplo mostra todos os triplos (gerados por Partition) e determina se o elemento do meio é menor que os dois extremos ou maior que os extremos.

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

Primeira solução

Isso encontra os triplos e examina os sinais das diferenças. Um extremo local retornará um {-1,1}ou {1,-1}.

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

Exemplo

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álise :

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

% refere-se ao resultado da respectiva linha 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 as triplas 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 o sinal (-, 0, +) das diferenças consista em a -1e a 1. No presente caso, são eles:

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

Para cada um desses casos, x, x[[2]]refere-se ao segundo termo. Esses serão todos os máximos e mínimos locais.

{10, 6, 9, 0, 1}


Seu estilo Mathematica é muito mais conciso que o meu. Quando começamos a chamá-lo de "Wolfram Language"?
Michael Stern


Michael Stern, suspeito que o Wolfram Language só se tornará oficial na versão 10, de alguma forma já disponível no Raspberry Pi.
DavidC

BTW, alguém inseriu uma linha de código que converte o ML de matemática em gráficos. Não sei por que.
DavidC

Não sei por que ele fez isso. Não consigo ver nenhuma diferença no código "modificado"
Dr. belisarius

6

J - 19 char

Não pude evitar;)

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

A explicação a seguir:

  • 2-/\] - Sobre cada par de elementos no argumento (cada infixo de 2 itens), faça a diferença.
  • 2*/\ - Agora, sobre cada par da nova lista, pegue o produto.
  • 0> - Teste se cada resultado é menor que 0. Isso só acontece se os multiplicandos tiverem sinais alternados, ou seja, não ocorrerá se eles tiverem o mesmo sinal ou forem zero.
  • 0, - Declare que o primeiro elemento não é um elemento extremo.
  • }: - Corte o último elemento, porque isso também não pode ser extremo.
  • #~ - Use os valores verdadeiros no lado direito para selecionar itens da lista no lado esquerdo.

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, isso pode não funcionar se a entrada for, digamos, 3, 4, 4, 4, 4, 5, ou seja, você pode obter um zero na etapa "0 =" se 0 for adicionado a 0.
Lord Soth

Além disso, não conheço esse idioma, mas, em vez de seguir o signum na primeira etapa, você pode deixar a diferença como está. Em seguida, na segunda etapa, multiplique os elementos e, na terceira, verifique se o produto é negativo (isso também evita o problema 0). Talvez isso possa resultar em um código mais curto.
Lord Soth 27/02

Boa captura e, sim, isso salva dois caracteres. Atualizando.
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)

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 os extremos locais em STDOUT.

Usa o <=>operador "nave espacial", que eu realmente gosto. (Ele retorna 1 se a primeira coisa for maior que a segunda, -1 se for menor e 0 se igual. Portanto, se adicionarem a -2 ou 2, isso significa que o meio é um extremo.)

Não é mais, como @daniero apontou que o caminho "óbvio" é realmente mais curto!

Alterado mais uma vez! Agora ele usa o incrível algoritmo encontrado na resposta do MT0 (+1 para ele!).

Além disso, eu gosto do each_consque seleciona cada ngrupo de elementos consecutivos em uma matriz. E arrastar também ifé interessante.

No geral, eu apenas gosto da aparência elegante.

Algumas amostras são executadas:

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

É mais curto para descompactar x em 3 variáveis:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero

@daniero Obrigado; Eu nem sabia que você poderia fazer isso! Editado
Maçaneta da porta

realmente ? : D Btw, agora que cada termo é 3 caracteres mais curto, é mais barato de fazer x>y&&y<z||x<y&&y>z(mesmo que o operador da nave espacial seja muito bonito);) #
daniero 27/02/2014

também ... !((x..z)===y)é ainda mais curto, embora não tão inteligente
Não é que Charles

@ Charles Isso falha quando x < z.
Maçaneta

3

C ++ - 208 caracteres

Solução mais longa novamente:

#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, digite seus números inteiros e, em seguida, qualquer caractere que irá travar o fluxo de entrada - qualquer caractere não numérico deve funcionar.

Entrada: 0 1 0 x

Resultado: 1


Você pode usar um em dequevez de um vectorpara ganhar 2 caracteres.
Morwenn 27/02

Além disso, em vez de usar ie j, você pode declarar int i;logo após a coleta e usar os dois loops em vez de declarar duas variáveis.
Morwenn 27/02

Finalmente, você provavelmente pode se livrar do incremento i++no loop for e iniciar sua condição if(v[++i]>[i-1]...para obter um caractere novamente.
Morwenn 27/02

2

Matlab - 45 bytes

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

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])]

Não é muito impressionante (observe todos os elementos da lista, exceto o primeiro e o último, veja se é maior ou menor que seus vizinhos). Estou postando principalmente porque nem todo mundo sabe que você pode fazer x<y>ze fazer funcionar. Eu acho isso meio legal.

Sim, x<y>zé um recurso interessante do python, mas não é realmente ideal neste caso. Graças a VX pelo truque de multiplicação, isso não me ocorreu. Wrzlprmft me lembrou que declarar uma função anônima é menos pressionamento de tecla do que def x(y):.


if(l[i]-l[i-1])*(l[i]-l[i+1])>0reduziria o código em 11 caracteres ...
VX

@wrz Ah, você está certo. Fiquei impressionado com o fato de ter def e(l):\n o mesmo número de caracteres e=lambda l:, mas esqueci que você não precisa usar a returnpalavra - chave. Obrigado!
Undergroundmonorail

@ vx Oh, eu gosto muito disso. Obrigado :) editar: Na verdade, você pode economizar mais do que isso! Desde que (l[i]-l[i-1])*(l[i]-l[i+1])é 1se l[i]é um extremo local e 0caso contrário, eu não preciso usar >0. Eu posso apenas deixar python interpretá-lo como um bool. :)
undergroundmonorail

@ wrz Não consigo descobrir como editar um comentário que já foi editado (o ícone de lápis parece substituir o botão de edição. é isso por design?). Eu só queria acrescentar que, se fosse inteligente, teria percebido que minha função de uma linha não precisava \n da declaração! Isso teria poupado dois caracteres, mas a inclusão de returnainda não vale a pena.
Undergroundmonorail

2

Haskell 50

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

1
isso só verifica o máximo local, pois o mínimo precisa adicionar || x <min pn
karakfa 27/02

x>p&&x>ntem um a menos do que o personagem x>max p n:-)
yatima2975

espaço depois ,também não é necessário.
karakfa

1
mudança x>p&&x>npara (x>p)==(x>n)para mínimos locais também, adiciona mais 4 caracteres.
Karakfa 9/07

2

Geléia , 8 bytes

IṠIỊ¬T‘ị

Experimente online!

Explicação

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

Um elemento é apenas um extremo local se sua diferença com o vizinho esquerdo tiver um sinal oposto à diferença com o vizinho direito, ou seja, os sinais das diferenças diferirem por 2 ou -2. O Jelly possui várias primitivas úteis para lidar com "encontrar elementos com certas propriedades" (em particular, podemos encontrar elementos com certas propriedades em uma lista e usá-la para extrair elementos de uma lista diferente), o que significa que podemos traduzir novamente para a lista original mais ou menos diretamente (só precisamos compensar por 1 porque o primeiro e o último elemento da lista original se perderam na diferença).


1

Python com Numpy - 81 74 67 bytes ( 61 54 sem a importlinha)

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

A entrada precisa ser uma matriz 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 caracteres

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

Não há esperança de derrotar uma linguagem como J ou APL por pouco tempo, mas pensei em jogar meu chapéu no ringue de qualquer maneira. Explicação:

  • Em um determinado momento, a, b, e cespera x_i,x_(i-1) ex_(i-2)
  • b-ce a-baproximar o derivado antes e depoisx_(i-1)
  • Se o produto for negativo, um é negativo e o outro é positivo x_(i-1); portanto, é um extremo local; portanto, imprima

1

Brachylog , 17 bytes

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

Experimente online!

Leva a entrada através da variável de entrada e gera a saída através da variável de saída.

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 execuções de valores pudessem estar ausentes, s₃{{⌉|⌋}.&bh}isso salvaria quatro bytes.



1

Wolfram Language (Mathematica) , 43 42 bytes

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

Experimente online!

Eu acho que Nothingé muito longo ...

#~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 bytes

¥.±¥Ä2Q0šÏ

Experimente online ou verifique mais alguns casos de teste .

Explicação:

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

Exemplo de uso:

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

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

0

Haskell, 70C

Versão Golfed

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

Versão 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 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}

0

APL, 19 bytes

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

Eu converti a versão J de 20 caracteres para APL. Mas adiciono um zero ao começo e ao fim, em vez de remover o primeiro e o último dígito. Caso contrário, funciona exatamente como a versão J.

- parâmetro formal ômega. Esta é a entrada para a função.


Enquanto estamos no assunto, eu tenho uma versão K, também, em 22 caracteres: {x@1+&0>2_*':-':0 0,x}. 6 desses caracteres (2_ e 0 0,) são gastos protegendo contra um erro de comprimento se o argumento for menor que dois itens, portanto, se não fosse por esse problema, seria 16 ... A ação também é um pouco diferente - precisamos ativar o lista booleana em uma lista de índices com 1+&e use-a para indexar xnovamente - mas é mais curto e também uma coisa muito K-ish a ser feita.
algorithmshark

Sua versão K superaria a minha versão APL então. Meu código precisa de pelo menos dois 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)

Experimente online!

Essa função evita principalmente os custosos negócios da indexação, tomando os elementos da lista como argumentos, em vez da própria lista. Embora exista mais de um elemento na lista, criamos recursivamente a lista, verificando o máximo em cada etapa.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.