Menemukan Ekstrem Lokal

14

Tulis fungsi atau program yang memuat daftar dan menghasilkan daftar ekstrem lokal.

Dalam daftar, [x_0, x_1, x_2...]ekstrim lokal adalah x_isedemikian rupa sehingga x_(i-1) < x_idan x_(i+1) < x_iatau x_(i-1) > x_idan x_(i+1) > x_i. Perhatikan bahwa elemen pertama dan terakhir dari daftar tidak pernah bisa menjadi ekstrem lokal.

Jadi untuk beberapa contoh

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

Ini kode golf sehingga kode terpendek menang!

Daniel Gratzer
sumber
Untuk memastikan saya mengerti dengan benar: Angka lebih besar dari angka di kedua sisi?
undergroundmonorail
@undergroundmonorail Lebih besar atau kurang dari. Jadi itu harus minimum lokal, di mana tetangganya lebih besar, atau maksimum di mana mereka berdua lebih kecil
Daniel Gratzer
Oh begitu. Saya salah baca
undergroundmonorail
2
dan bagaimana dengan urutan yang 1 2 2 1seharusnya tidak 2dianggap sebagai ekstrem juga? - Saya tahu, ini akan membuat solusinya jauh lebih sulit ...
VX

Jawaban:

5

Mathematica 66 58 51

Solusi Saat Ini

Dipersingkat berkat sumbangan dari Calle.

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

Partition[#,3,1] menemukan tiga kali lipat.

(a-b) (b-c)<0adalah benar jika dan hanya jika bdi bawah a, catau di atas a, c. dan melihat mengambil tanda-tanda perbedaan. Ekstrim lokal akan mengembalikan salah satu {-1,1}atau {1,-1}.


Contohnya

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}


Solusi Sebelumnya

Ini terlihat contoh semua tiga kali lipat (dihasilkan oleh Partition) dan menentukan apakah elemen tengah kurang dari kedua ekstrem atau lebih besar dari ekstrem.

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

Solusi Pertama

Ini menemukan tiga kali lipat, dan melihat mengambil tanda-tanda perbedaan. Ekstrim lokal akan mengembalikan salah satu {-1,1}atau {1,-1}.

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

Contoh

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}


Analisis :

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

% merujuk pada hasil dari baris sebelumnya masing-masing.

Differences/@ %

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

Sort@Sign@Differences@x=={-1,1}mengidentifikasi tiga kali lipat dari {{9, 10, 7}, {10, 7, 6}, {7, 6, 9}, {6, 9, 0}, {9, 0, 3}, {0, 3, 3}, {3, 3, 1}, {3, 1, 10}} sedemikian rupa sehingga tanda (-, 0, +) dari perbedaan terdiri dari a -1dan a 1. Dalam hal ini adalah:

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

Untuk masing-masing kasus ini, x, x[[2]]mengacu pada istilah kedua. Itu semua akan menjadi maxima dan minima lokal.

{10, 6, 9, 0, 1}

DavidC
sumber
Gaya Mathematica Anda jauh lebih ringkas daripada gaya saya. Kapan kita mulai menyebutnya "Bahasa Wolfram"?
Michael Stern
Saya melihat ini! Grafik Mathematica
Dr. belisarius
Michael Stern, saya curiga Bahasa Wolfram hanya akan menjadi resmi di versi 10, beberapa bentuk yang sudah tersedia di Raspberry Pi.
DavidC
BTW, seseorang memasukkan sederet kode yang mengubah Math ML menjadi grafik. Saya tidak yakin mengapa.
DavidC
Saya tidak yakin mengapa dia melakukannya. Saya tidak dapat melihat perbedaan dalam kode "modifikasi"
Dr. belisarius
6

J - 19 char

Tidak bisa menahannya;)

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

Penjelasan berikut:

  • 2-/\] - Atas setiap pasangan elemen dalam argumen (masing-masing infix panjang 2-item), ambil perbedaannya.
  • 2*/\ - Sekarang untuk setiap pasang daftar baru, ambil produk.
  • 0> - Uji apakah masing-masing hasil kurang dari 0. Ini hanya terjadi jika multiplikasi memiliki tanda bolak-balik, yaitu tidak terjadi jika mereka memiliki tanda yang sama atau salah satu dari nol.
  • 0, - Nyatakan bahwa elemen pertama bukanlah elemen ekstrem.
  • }: - Potong elemen terakhir, karena itu tidak mungkin menjadi ekstrim juga.
  • #~ - Gunakan nilai sebenarnya di sisi kanan untuk memilih item dari daftar di sisi kiri.

Pemakaian:

   (}:#~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
algoritme hiu
sumber
Umm, ini mungkin tidak berfungsi jika inputnya, katakanlah, 3, 4, 4, 4, 4, 5, yaitu Anda mungkin mendapatkan nol pada langkah "0 =" jika 0 ditambahkan ke 0.
Lord Soth
Juga, saya tidak tahu tentang bahasa ini, tetapi alih-alih mengambil signum pada langkah pertama, Anda dapat membiarkan perbedaannya apa adanya. Kemudian, pada langkah kedua, gandakan elemen, dan pada langkah ketiga Anda dapat memeriksa apakah produk negatif (ini juga menghindari masalah 0). Mungkin ini dapat menghasilkan kode yang lebih pendek.
Lord Soth
Tangkapan yang bagus, dan ya, ini menghemat dua karakter. Memperbarui.
algorithmshark
5

Javascript - 62 45 Karakter

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

Edit

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

Ruby, 83 70 60 55 49 karakter

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

Mencetak semua ekstrem lokal ke STDOUT.

Menggunakan <=>operator "pesawat ruang angkasa", yang sangat saya sukai. (Mengembalikan 1 jika hal pertama lebih besar dari yang kedua, -1 jika lebih kecil, dan 0 jika sama. Karena itu, jika mereka menambah -2 atau 2, itu berarti tengah adalah ekstrim.)

Tidak lagi, seperti yang ditunjukkan oleh @daniero bahwa cara "jelas" sebenarnya lebih pendek!

Berubah lagi! Sekarang menggunakan algoritma luar biasa yang ditemukan dalam jawaban MT0 (+1 kepadanya!).

Juga, saya suka each_consyang memilih setiap ngrup elemen berurutan dalam sebuah array. Dan trailing ifjuga menarik.

Secara keseluruhan, saya suka betapa elegan tampilannya.

Beberapa contoh dijalankan:

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
Gagang pintu
sumber
Lebih pendek untuk membongkar x menjadi 3 variabel:f=->a{a.each_cons(3){|x,y,z|p y if((x<=>y)+(z<=>y)).abs==2}}
daniero
@daniero Terima kasih; Aku bahkan tidak tahu kamu bisa melakukan itu! Diedit
Gagang Pintu
benarkah ? : D Btw, sekarang setiap istilah lebih pendek 3 karakter, secara keseluruhan lebih murah untuk dilakukan x>y&&y<z||x<y&&y>z(bahkan operator ruang angkasa sangat cantik);)
daniero
juga ... !((x..z)===y)bahkan lebih pendek meskipun tidak sepintar
Bukan karena Charles
@ Charles Itu gagal saat x < z.
Gagang Pintu
3

C ++ - 208 karakter

Solusi terlama lagi:

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

Untuk menggunakan, masukkan bilangan bulat Anda, maka karakter apa pun yang akan merusak aliran input - karakter non-angka apa pun harus berfungsi.

Memasukkan: 0 1 0 x

Keluaran: 1


sumber
Anda dapat menggunakan dequealih - alih a vectoruntuk mendapatkan 2 karakter.
Morwenn
Selain itu, alih-alih menggunakan idan j, Anda dapat mendeklarasikan int i;tepat setelah pengumpulan dan menggunakannya adalah dua loop, bukan mendeklarasikan dua variabel.
Morwenn
Akhirnya, Anda mungkin bisa menyingkirkan kenaikan tersebut i++ dalam for for loop Anda dan memulai kondisi Anda dengan if(v[++i]>[i-1]...tujuan untuk mendapatkan satu karakter lagi.
Morwenn
2

Matlab - 45 byte

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

Tidak terlalu mengesankan (Lihat setiap elemen daftar kecuali yang pertama dan terakhir, lihat apakah itu lebih besar atau lebih kecil dari tetangganya). Saya kebanyakan hanya mempostingnya karena tidak semua orang tahu Anda bisa melakukannya x<y>zdan membuatnya berfungsi. Saya pikir itu agak rapi.

Ya, x<y>zadalah fitur keren dari python, tetapi sebenarnya tidak optimal dalam hal ini. Berkat VX untuk trik multiplikasi, itu tidak terjadi pada saya sama sekali. Wrzlprmft mengingatkan saya bahwa mendeklarasikan fungsi anonim lebih sedikit penekanan daripada def x(y):.

monmon bawah tanah
sumber
if(l[i]-l[i-1])*(l[i]-l[i+1])>0akan mengurangi kode sebanyak 11 karakter ...
VX
@wrz Ah, kamu benar. Saya terlempar oleh fakta bahwa def e(l):\n jumlah karakter yang sama e=lambda l:, tetapi saya lupa bahwa Anda tidak perlu menggunakan returnkata kunci. Terima kasih!
undergroundmonorail
@ Vx Oh, saya sangat menyukainya. Terima kasih :) sunting: Sebenarnya Anda dapat menyimpan lebih dari itu! Sejak (l[i]-l[i-1])*(l[i]-l[i+1])adalah 1jika l[i]adalah ekstrim lokal dan 0jika tidak, saya tidak perlu menggunakan >0. Saya bisa membiarkan python menafsirkannya sebagai bool. :)
undergroundmonorail
@wrz Saya tidak tahu cara mengedit komentar yang sudah diedit (ikon pensil sepertinya menggantikan tombol edit. apakah ini sesuai desain?). Saya hanya ingin menambahkan bahwa, jika saya pintar, saya akan menyadari bahwa fungsi satu-baris saya tidak memerlukan \n sama sekali dalam deklarasi! Itu akan menyelamatkan dua karakter, tetapi dimasukkannya returnmasih membuatnya tidak layak.
undergroundmonorail
2

Haskell 50

f a=[x|(p,x,n)<-zip3 a(tail a)(drop 2 a),x>p&&x>n]
karakfa
sumber
1
ini hanya memeriksa maksimum lokal, untuk minumum perlu menambahkan || x <min pn
karakfa
x>p&&x>nmemiliki satu karakter lebih sedikit dari x>max p n:-)
yatima2975
ruang setelah ,tidak diperlukan juga.
karakfa
1
ubah x>p&&x>nmenjadi (x>p)==(x>n)minimum lokal juga, tambahkan 4 karakter lagi.
karakfa
2

Jelly , 8 byte

IṠIỊ¬T‘ị

Cobalah online!

Penjelasan

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

Suatu elemen hanya merupakan ekstrim lokal jika perbedaannya dengan tetangga kirinya memiliki tanda yang berlawanan dengan perbedaannya dengan tetangga kanannya, yaitu tanda-tanda perbedaannya berbeda 2 atau -2. Jelly memiliki sejumlah primitif yang berguna untuk berurusan dengan "menemukan elemen dengan properti tertentu" (khususnya, kita dapat menemukan elemen dengan properti tertentu dalam satu daftar dan menggunakannya untuk mengekstrak elemen dari daftar yang berbeda), artinya kita dapat menerjemahkan kembali ke daftar asli kurang lebih secara langsung (kita hanya perlu mengimbangi dengan 1 karena elemen pertama dan terakhir dari daftar asli hilang dalam pengambilan perbedaan).

ais523
sumber
1

Python dengan Numpy - 81 74 67 byte ( 61 54 tanpa importgaris)

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

Input harus berupa array Numpy.

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

awk - 32 karakter

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

Tidak ada harapan mengalahkan bahasa seperti J atau APL pada singkatnya, tapi saya pikir saya akan tetap memakai topiku. Penjelasan:

  • Pada waktu tertentu, a, b, dan cterus x_i, x_(i-1)danx_(i-2)
  • b-cdan a-bperkiraan turunannya sebelum dan sesudahx_(i-1)
  • Jika produk mereka negatif, maka yang satu negatif dan yang lain positif x_(i-1), karenanya ekstrem lokal, jadi cetak
laindir
sumber
1

Brachylog , 17 byte

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

Cobalah online!

Mengambil input melalui variabel input dan menghasilkan output melalui variabel 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.

Jika menjalankan nilai dapat dijamin tidak ada, s₃{{⌉|⌋}.&bh}akan menghemat empat byte.

String yang tidak terkait
sumber
1

Perl 5 -p , 49 byte

s/\d+ (?=(\d+) (\d+))/say$1if($1-$&)*($1-$2)>0/ge

Cobalah online!

Xcali
sumber
1

Bahasa Wolfram (Mathematica) , 43 42 byte

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

Cobalah online!

Saya kira Nothingterlalu panjang ...

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

05AB1E , 11 10 byte

¥.±¥Ä2Q0šÏ

Cobalah secara online atau verifikasi beberapa kasus uji lagi .

Penjelasan:

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

Contoh penggunaan:

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

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

Haskell, 70C

Versi 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 tidak disatukan

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

Javascript: 102 karakter

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

APL, 19 byte

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

Saya mengonversi versi 20 char J ke APL. Tapi saya menambahkan nol ke awal dan akhir bukannya menghapus digit pertama dan terakhir. Kalau tidak, ia berfungsi seperti versi J.

- parameter formal omega. Ini adalah input ke fungsi.

pengguna10639
sumber
Sementara kami berada di itu, saya memiliki versi K, juga, dalam 22 karakter: {x@1+&0>2_*':-':0 0,x}. 6 dari karakter ini ( 2_dan 0 0,) dihabiskan untuk melindungi dari kesalahan panjang jika argumen lebih pendek dari dua item, jadi jika bukan karena masalah itu akan menjadi 16 ... Aksi juga sedikit berbeda - kita harus mengubah daftar boolean ke dalam daftar indeks dengan 1+&dan menggunakannya untuk mengindeks xlagi - tetapi lebih pendek dan juga hal yang sangat K-ish untuk dilakukan.
algorithmshark
Versi K Anda akan mengalahkan versi APL saya. Kode saya membutuhkan setidaknya dua angka.
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)

Cobalah online!

Fungsi ini sebagian besar menghindari bisnis pengindeksan yang mahal, dengan mengambil elemen daftar sebagai argumen, alih-alih daftar itu sendiri. Meskipun ada lebih dari satu elemen yang tersisa dalam daftar, kami secara rekursif membangun daftar, memeriksa maksimum pada setiap langkah.

ArBo
sumber