Trouver des extrêmes locaux

14

Écrivez une fonction ou un programme qui prend une liste et produit une liste des extrêmes locaux.

Dans une liste, [x_0, x_1, x_2...]un extrême local est x_itel que x_(i-1) < x_iet x_(i+1) < x_iou x_(i-1) > x_iet x_(i+1) > x_i. Notez que les premier et dernier éléments de la liste ne peuvent jamais être des extrêmes locaux.

Donc, pour quelques exemples

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

C'est le golf de code, donc le code le plus court gagne!

Daniel Gratzer
la source
Pour être sûr de bien comprendre: des nombres supérieurs aux nombres de chaque côté?
undergroundmonorail
@undergroundmonorail Supérieur ou inférieur à. Il faut donc que ce soit un minimum local, où ses voisins sont tous les deux plus grands, ou un maximum où ils sont tous deux plus petits
Daniel Gratzer
Oh je vois. Je l'ai mal lu
undergroundmonorail
2
et qu'en est-il de la séquence 1 2 2 1ne devrait-elle pas aussi 2être considérée comme des extrêmes? - Je sais, cela rendrait la solution beaucoup plus difficile ...
VX

Réponses:

5

Mathematica 66 58 51

Solution actuelle

Raccourci grâce à une contribution de Calle.

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

Partition[#,3,1] trouve les triplets.

(a-b) (b-c)<0est vrai si et seulement si best inférieure a, cou au- dessus a, c. et regarde prend les signes des différences. Un extrême local retournera soit {-1,1}ou {1,-1}.


Exemples

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}


Solution antérieure

Cela ressemble à des exemples de tous les triplets (générés par Partition) et détermine si l'élément central est inférieur aux deux extrêmes ou supérieur aux extrêmes.

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

Première solution

Cela trouve les triplets, et regarde prend les signes des différences. Un extrême local retournera soit {-1,1}ou {1,-1}.

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

Exemple

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

% fait référence au résultat de la ligne précédente respective.

Differences/@ %

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

Sort@Sign@Differences@x=={-1,1}identifie les triplets parmi {{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 telle sorte que le signe (-, 0, +) des différences se compose de a -1et a 1. Dans le cas présent, ce sont:

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

Pour chacun de ces cas, x x[[2]]fait référence au deuxième terme. Ce seront tous les maxima et minima locaux.

{10, 6, 9, 0, 1}

DavidC
la source
Votre style Mathematica est beaucoup plus concis que le mien. Quand commençons-nous à l'appeler "Wolfram Language"?
Michael Stern
Je vois ça ! Graphiques Mathematica
Dr. belisarius
Michael Stern, je soupçonne que Wolfram Language ne deviendra officiel qu'à la version 10, dont une forme est déjà disponible sur Raspberry Pi.
DavidC
BTW, quelqu'un a inséré une ligne de code qui convertit le Math ML en graphiques. Je ne sais pas pourquoi.
DavidC
Je ne sais pas pourquoi il l'a fait. Je ne vois aucune différence dans le code "modifié"
Dr. belisarius
6

J - 19 caractères

Je n'ai pas pu l'aider;)

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

L'explication suit:

  • 2-/\] - Sur chaque paire d'éléments dans l'argument (chaque infixe long de 2 éléments), prenez la différence.
  • 2*/\ - Maintenant, sur chaque paire de la nouvelle liste, prenez le produit.
  • 0> - Testez si chaque résultat est inférieur à 0. Cela ne se produit que si les multiplicandes avaient des signes alternés, c'est-à-dire que cela ne se produit pas s'ils avaient le même signe ou l'un ou l'autre était nul.
  • 0, - Déclarez que le premier élément n'est pas un élément extrême.
  • }: - Coupez le dernier élément, car cela ne peut pas non plus être un extrême.
  • #~ - Utilisez les vraies valeurs sur le côté droit pour choisir des éléments dans la liste sur le côté gauche.

Usage:

   (}:#~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
la source
Umm, cela peut ne pas fonctionner si l'entrée est, disons, 3, 4, 4, 4, 4, 5, c'est-à-dire que vous pouvez obtenir un zéro à l'étape "0 =" si 0 est ajouté à 0.
Lord Soth
De plus, je ne connais pas cette langue, mais, au lieu de prendre le signal à la première étape, vous pouvez laisser la différence telle quelle. Ensuite, dans la deuxième étape, multipliez les éléments à la place, et dans la troisième, vous pouvez vérifier si le produit est négatif (cela évite également ce problème 0). Cela peut peut-être entraîner un code plus court.
Lord Soth
Bonne prise, et oui, cela sauve deux caractères. Mise à jour.
algorithmshark
5

Javascript - 62 45 caractères

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

Éditer

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

Rubis, 83 70 60 55 49 caractères

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

Imprime tous les extrêmes locaux dans STDOUT.

Utilise l' <=>opérateur "vaisseau spatial", que j'aime beaucoup. (Il renvoie 1 si la première chose est supérieure à la seconde, -1 si elle est inférieure et 0 si elle est égale. Par conséquent, s'ils ajoutent à -2 ou 2, cela signifie que le milieu est un extrême.)

Ce n'est plus le cas, car @daniero a souligné que le chemin "évident" est en fait plus court!

Changé encore une fois! Maintenant, il utilise l'algorithme génial trouvé dans la réponse de MT0 (+1 pour lui!).

Aussi, j'aime each_consqui sélectionne chaquen groupe d'éléments consécutifs dans un tableau. Et le suivi ifest également intéressant.

Dans l'ensemble, j'aime son élégance.

Quelques exemples d'exécutions:

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
Poignée de porte
la source
Il est plus court de décompresser x en 3 variables:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero
@daniero Merci; Je ne savais même pas que tu pouvais faire ça! Modifié
Poignée de porte
vraiment ? : D Btw, maintenant que chaque terme est plus court de 3 caractères, c'est globalement moins cher à faire x>y&&y<z||x<y&&y>z(même si l'opérateur du vaisseau spatial est très joli);)
daniero
aussi ... !((x..z)===y)est encore plus court mais pas aussi intelligent
Pas que Charles
@Charles Cela échoue quand x < z.
Poignée de porte
3

C ++ - 208 caractères

Encore la solution la plus longue:

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

Pour l'utiliser, entrez vos nombres entiers, puis tout caractère qui plantera le flux d'entrée - tous les caractères non numériques devraient fonctionner.

Contribution: 0 1 0 x

Production: 1


la source
Vous pouvez utiliser un dequeau lieu d'un vectorpour gagner 2 personnages.
Morwenn
De plus, au lieu d'utiliser iet j, vous pouvez déclarer int i;juste après la collecte et utiliser dans les deux boucles au lieu de déclarer deux variables.
Morwenn
Enfin, vous pouvez probablement vous débarrasser de l'incrément i++dans votre boucle for et commencer votre condition if(v[++i]>[i-1]...afin de gagner à nouveau un personnage.
Morwenn
2

Matlab - 45 octets

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

Python 2.7 - 73 octets

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

Pas trop impressionnant (regardez chaque élément de la liste sauf le premier et le dernier, voyez s'il est plus grand ou plus petit que ses voisins). Je ne le poste que parce que tout le monde ne sait pas que vous pouvez le faire x<y>zet le faire fonctionner. Je pense que c'est plutôt bien.

Oui, x<y>zc'est une fonctionnalité intéressante de python, mais ce n'est pas réellement optimal dans ce cas. Merci à VX pour l'astuce de multiplication, cela ne m'est pas venu du tout à l'esprit. Wrzlprmft m'a rappelé que déclarer une fonction anonyme représente moins de touches que def x(y):.

métro monorail
la source
if(l[i]-l[i-1])*(l[i]-l[i+1])>0réduirait le code de 11 caractères ...
VX
@wrz Ah, vous avez raison. J'ai été bouleversé par le fait que def e(l):\n c'est le même nombre de caractères que e=lambda l:, mais j'ai oublié que vous n'avez pas besoin d'utiliser le returnmot - clé. Merci!
undergroundmonorail
@vx Oh, j'aime beaucoup ça. Merci :) edit: En fait, vous pouvez économiser plus que cela! Puisque (l[i]-l[i-1])*(l[i]-l[i+1])c'est 1si l[i]est un extrême local et 0sinon, je n'ai pas besoin de l'utiliser >0. Je peux simplement laisser python l'interpréter comme un booléen. :)
undergroundmonorail
@wrz Je n'arrive pas à comprendre comment modifier un commentaire qui a déjà été modifié (l'icône de crayon semble remplacer le bouton de modification. Est-ce par conception?). Je voulais juste ajouter que, si j'étais intelligent, j'aurais réalisé que ma fonction à une ligne n'avait pas du tout besoin de la \n dans la déclaration! Cela aurait sauvé deux caractères, mais l'inclusion de returnn'en vaut pas la peine.
undergroundmonorail
2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]
karakfa
la source
1
cela ne vérifie que le maximum local, car le minimum doit ajouter || x <min pn
karakfa
x>p&&x>na un caractère de moins que x>max p n:-)
yatima2975
l'espace ,n'est pas non plus nécessaire.
karakfa
1
le changement x>p&&x>nà (x>p)==(x>n)des minimums locaux aussi, ajoute 4 autres caractères.
karakfa
2

Gelée , 8 octets

IṠIỊ¬T‘ị

Essayez-le en ligne!

Explication

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 élément n'est un extrême local que si sa différence avec son voisin gauche a un signe opposé à sa différence avec son voisin droit, c'est-à-dire que les signes des différences diffèrent de 2 ou -2. Jelly a un certain nombre de primitives utiles pour traiter "trouver des éléments avec certaines propriétés" (en particulier, nous pouvons trouver des éléments avec certaines propriétés dans une liste et l'utiliser pour extraire des éléments d'une liste différente), ce qui signifie que nous pouvons traduire en la liste d'origine plus ou moins directement (il suffit de compenser de 1 car les premier et dernier éléments de la liste d'origine se sont perdus dans la prise de différence).

ais523
la source
1

Python avec Numpy - 81 74 67 octets ( 61 54 sans la importligne)

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

L'entrée doit être un tableau Numpy.

Wrzlprmft
la source
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
la source
1

awk - 32 caractères

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

Aucun espoir de battre un langage comme J ou APL par souci de concision, mais je pensais que je jetterais mon chapeau dans le ring de toute façon. Explication:

  • À un moment donné, a, bet ctenir x_i, x_(i-1)etx_(i-2)
  • b-c et a-b approximer la dérivée avant et aprèsx_(i-1)
  • Si leur produit est négatif, alors l'un est négatif et l'autre est positif, c'est donc x_(i-1)un extrême local, alors imprimez
laindir
la source
1

Brachylog , 17 octets

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

Essayez-le en ligne!

Prend l'entrée via la variable d'entrée et génère la sortie via la variable de sortie.

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 des séries de valeurs pouvaient être assurées d'être absentes, s₃{{⌉|⌋}.&bh}cela économiserait quatre octets.

Chaîne indépendante
la source
1

Wolfram Language (Mathematica) , 43 42 octets

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

Essayez-le en ligne!

Je suppose que Nothingc'est trop long ...

#~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
la source
1

05AB1E , 11 10 octets

¥.±¥Ä2Q0šÏ

Essayez-le en ligne ou vérifiez quelques cas de test supplémentaires .

Explication:

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

Exemple d'utilisation:

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

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

Haskell, 70C

Version golfée

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

Version non golfée

-- 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
la source
0

Javascript: 102 caractères

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
la source
0

APL, 19 octets

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

J'ai converti la version J 20 caractères en APL. Mais j'ajoute un zéro au début et à la fin au lieu de supprimer le premier et le dernier chiffre. Sinon, cela fonctionne exactement comme la version J.

- paramètre formel oméga. Il s'agit de l'entrée de la fonction.

user10639
la source
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.

ArBo
la source