寻找局部极端


14

编写一个接受列表并生成局部极值列表的函数或程序。

在列表[x_0, x_1, x_2...]局部极值是x_i这样x_(i-1) < x_ix_(i+1) < x_ix_(i-1) > x_ix_(i+1) > x_i。请注意,列表的第一个和最后一个元素永远不能是局部极值。

所以对于一些例子

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

这是代码高尔夫球,所以最短的代码获胜!


为了确保我正确理解:数字是否大于两侧的数字?
地下

@undergroundmonorail大于或小于。因此,它要么必须是邻居的最大值都较小的局部最小值,要么应是它们的最小值都较小的最大值
Daniel Gratzer 2014年

哦,我懂了。我看错了
undergroundmonorail

2
顺序1 2 2 1又该2怎么办呢?-我知道,这会使解决方案更加困难...
VX

Answers:


5

Mathematica 66 58 51

当前解决方案

由于Calle的贡献而缩短了。

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

Partition[#,3,1] 找到三元组。

(a-b) (b-c)<0为真,当且仅当b以下是ac,或以上ac。然后看一下差异的迹象。局部极值将返回{-1,1}{1,-1}


例子

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}


较早的解决方案

该示例查找所有三元组(由生成Partition)的示例,并确定中间元素是否小于两个极端或大于两个极端。

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

第一个解决方案

这将查找三元组,并查看差异的迹象。局部极值将返回{-1,1}{1,-1}

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

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,9,0,1}


分析

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

% 是指相应的前一行的结果。

Differences/@ %

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

Sort@Sign@Differences@x=={-1,1}从{{9,10,7},{10,7,6},{7,6,9},{6,9,0},{9,0,3},{0,3, 3},{3、3、1},{3、1、10}},使得差异的符号(-,0,+)由a -1和a组成1。在当前情况下,这些是:

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

对于每种情况,x x[[2]]都是第二项。这些将是所有局部最大值和最小值。

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


您的Mathematica风格比我的简洁得多。我们什么时候开始将其称为“ Wolfram语言”?
迈克尔·斯特恩


迈克尔·斯特恩(Michael Stern),我怀疑Wolfram语言只会在版本10上才成为正式版本,而其中的某些形式已在Raspberry Pi上提供。
DavidC

顺便说一句,有人插入了一行代码,将Math ML转换为图形。我不知道为什么。
DavidC

我不确定他为什么这么做。我看不到“修改后的”代码中的任何区别
belisarius博士2014年

6

J-19个字符

无法帮助;)

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

解释如下:

  • 2-/\] -在参数中的每对元素上(每个元素有2个项目的长缀),取其差值。
  • 2*/\ -现在,在每对新清单上,拿起产品。
  • 0> -测试每个结果是否小于0。仅在被乘数具有交替符号的情况下才会发生,即,如果被乘数具有相同的符号或两个都为零,则不会发生。
  • 0, -声明第一个元素不是极端元素。
  • }: -切掉最后一个元素,因为那也不可能是极端的。
  • #~ -使用右侧的true值从左侧列表中选择项目。

用法:

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

嗯,这个,如果输入的是,比如说,3,4,4,4,4,5可能无法正常工作,例如,你可能会在“0 =”一步一个零,如果0添加到0
索斯爵士

另外,我也不了解这种语言,但是,您不必先采取这种方法,而可以保持原样。然后,在第二步中,乘以元素,然后在第三步中,检查乘积是否为负(这也避免了0问题)。也许这可能会导致代码更短。
索思勋爵2014年

不错,是的,这样可以节省两个字符。正在更新。
algorithmhark

5

Javascript- 62 45个字符

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

编辑

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

4

Ruby,83 70 60 55 49个字符

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

将所有局部极值打印到STDOUT。

使用 <=>我非常喜欢 “太空飞船”运算符。(如果第一件事大于第二件事,则返回1;如果第二件事小于第二点,则返回-1;如果相等则返回0。因此,如果它们相加为-2或2,则意味着中间值是极端。)

就像@daniero指出的那样,“显而易见”的方法实际上更短了,不再有用了!

再次改变!现在,它使用了 MT0答案中(对他+1!)。

另外,我喜欢在数组中each_cons选择每组n连续元素。和尾随if也很有趣。

总的来说,我喜欢它的外观。

一些示例运行:

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

将x解压缩为3个变量的时间较短:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero 2014年

@daniero谢谢;我什至不知道你能做到!编辑
门把手

真的吗?:D顺便说一句,现在每学期缩短3个字符,这样做总的来说更便宜x>y&&y<z||x<y&&y>z(即使太空飞船的操作员都很漂亮);)
daniero 2014年

还有... !((x..z)===y)甚至更短,虽然不那么聪明
并不是说Charles

@Charles在时失败x < z
门把手

3

C ++-208个字符

最长的解决方案:

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

要使用该命令,请输入整数,然后输入任何会导致输入流崩溃的字符-任何非数字字符都可以使用。

输入: 0 1 0 x

输出: 1


您可以使用a deque代替a vector获得2个字符。
Morwenn 2014年

另外,除了使用iand之外j,还可以int i;在集合之后声明并使用in是两个循环,而不是声明两个变量。
Morwenn 2014年

最后,您可能可以摆脱i++for循环中的增量,并开始您的条件以if(v[++i]>[i-1]...再次获得一个字符。
Morwenn 2014年


2

Python 2.7-73个字节

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

不太令人印象深刻(查看列表中的每个元素,除了第一个和最后一个元素,看看它是否大于其邻居)。我主要只是发布它,因为不是每个人都知道您可以做到x<y>z并使其正常运行。我认为这很整洁。

是的,这x<y>z是python的一个很酷的功能,但在这种情况下实际上并不是最佳的。感谢VX的乘法技巧,这对我完全没有。Wrzlprmft提醒我,声明匿名函数比少击键def x(y):


if(l[i]-l[i-1])*(l[i]-l[i+1])>0将减少11个字符的代码...
VX

@wrz啊,你是对的。def e(l):\n 字符数与相同的事实使e=lambda l:我震惊,但我忘记了您不需要使用return关键字。谢谢!
地下

@vx哦,我非常喜欢。谢谢:) 编辑:实际上,您可以节省更多!由于(l[i]-l[i-1])*(l[i]-l[i+1])is 1if l[i]是一个局部极端,0否则,我不需要使用>0。我可以让python将其解释为bool。:)
Undergroundmonorail

@wrz我不知道如何编辑已被编辑的注释(铅笔图标似乎代替了编辑按钮。这是设计使然吗?)。我只是想补充一下,如果我很聪明,我会意识到我的单行函数根本不需要\n 在声明中!那样可以节省两个字符,但是包含return仍然不值得。
地下


2

果冻,8字节

IṠIỊ¬T‘ị

在线尝试!

说明

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

如果一个元素与其左邻居的差异与其右邻居的差异具有相反的符号,即,差异的符号相差2或-2,则该元素仅是局部极值。Jelly具有许多有用的原语,用于处理“查找具有某些属性的元素”(特别是,我们可以在一个列表中找到具有某些属性的元素,并使用该元素从其他列表中提取元素),这意味着我们可以将其转换回原始列表或多或少直接地(我们只需要偏移1,因为原始列表的第一个和最后一个元素在进行求差时会丢失)。


1

带有Numpy的Python – 81 74 67字节(无行的61 54 import

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

输入必须是一个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个字符

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

简短地说,打败J或APL之类的语言是没有希望的,但是我认为无论如何我还是会戴上帽子。说明:

  • 在任何给定时间ab以及c保持x_ix_(i-1)以及x_(i-2)
  • b-ca-b估算前后的导数x_(i-1)
  • 如果它们的乘积为负,则一个为负,另一个为正,x_(i-1)因此为局部极值,因此打印

1

Brachylog,17个字节

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

在线尝试!

通过输入变量获取输入,并通过输出变量生成输出。

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.

如果可以保证不存在值的运行,s₃{{⌉|⌋}.&bh}则将节省四个字节。



1

Wolfram语言(Mathematica)43 42字节

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

在线尝试!

我想Nothing太久了...

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

05AB1E11 10 字节

¥.±¥Ä2Q0šÏ

在线尝试验证更多测试用例

说明:

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

用法示例:

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

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

0

Haskell,70℃

高尔夫版

e(a:b:c:r)
 |a<b&&b>c||a>b&&b<c=b:s
 |True=s
 where s=e(b:c:r)
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 _ = []


0

APL,19个字节

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

我将20 char J版本转换为APL。但是我在开头和结尾添加了零,而不是删除了第一位和最后一位。否则,它将像J版本一样工作。

-正式参数Ω。这是功能的输入。


当我们使用它时,我也有一个K版本的22个字符:{x@1+&0>2_*':-':0 0,x}。如果参数短于两个项目,则其中的6个字符(2_0 0,)用于防止长度错误,因此,如果不是针对该问题,则为16。将boolean list转换为索引列表,1+&并使用它x再次索引-但是它更短,也是一件非常K类的事情。
algorithmhark

您的K版本会胜过我的APL版本。我的代码至少需要两个数字。
user10639

0

Python 2,59个字节

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

在线尝试!

此功能通过将列表的元素(而不是列表本身)作为参数来避免索引的昂贵工作。尽管列表中还剩下一个以上的元素,但我们以递归方式建立列表,并在每一步中检查最大值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.