Nth Differences


26

In matematica, un modo per capire quale sia il tipo di una data relazione (lineare, quadratica, ecc.) È calcolare le differenze. Per fare ciò, prendi un elenco di valori y per i quali lo spazio tra i corrispondenti valori x è lo stesso e sottrai ciascuno dal numero sopra di esso, creando un elenco di numeri uno più corto dell'elenco precedente. Se l'elenco risultante è completamente composto da numeri identici, la relazione ha una differenza di 1 (è lineare). Se non sono identici, ripeti il ​​processo sul nuovo elenco. Se ora sono identici, la relazione ha una differenza di 2 (è quadratica). Se non sono identici, è sufficiente continuare questo processo fino a quando non lo sono. Ad esempio, se si dispone dell'elenco di valori y [1,6,15,28,45,66] per aumentare in modo incrementale i valori x:

First Differences:

1
6   1-6  =-5
15  6-15 =-9
28  15-28=-13
45  28-45=-17
66  45-66=-21

Second differences:

-5 
-9  -5+9  =4
-13 -9+13 =4
-17 -13+17=4
-21 -17+21=4

As these results are identical, this relation has a difference of 2

Il tuo compito:

Scrivi un programma o una funzione che, quando viene fornita una matrice di numeri interi come input, restituisce la differenza della relazione descritta dalla matrice, come spiegato sopra.

Ingresso:

Un array di numeri interi, che può essere di qualsiasi lunghezza> 1.

Produzione:

Un numero intero che rappresenta la differenza della relazione descritta dall'input.

Casi test:

Input                            => Output
[1,2,3,4,5,6,7,8,9,10]           => 1
[1,4,9,16,25,36]                 => 2
[1,2,1]                          => 2 (when there is only one value left, all values are automatically identical, so the largest difference an array can have is equal to the length of the array-1)
"Hello World"                    => undefined behavior (invalid input)
[1,1,1,1,1,1,1,1,1]              => 0 (all elements are already identical)
[1, 3, 9, 26, 66, 150, 313, 610] => 6

punteggio:

Questo è , il punteggio più basso in byte in ogni lingua vince per quella lingua. Il punteggio più basso in assoluto ottiene il segno di spunta verde.


È possibile che l'input sia "non valido" come in, se l'input NON è conforme alle specifiche fornite, dovremmo sbagliare? Fornire -1 come output?
Magic Octopus Urn,

Il comportamento non è definito per input non valido (non mi interessa cosa fa il tuo codice)
Gryphon - Reinstalla Monica

Non dovresti [1,2,1]dare 2?[1,2,1] -> [1,-1] -> [-2]
HyperNeutrino,

@HyperNeutrino, sì, scusa. Lì ho avuto una scoreggia cerebrale
Gryphon - Reinstata Monica

Aggiungi questo caso di prova [1,3,9,26,66,150,313,610]-> 6se ti piace
J42161217

Risposte:


10

Buccia , 6 byte

Grazie Leo per avermi permesso di usare la sua versione per cui funziona[1,1,1,1,1,1]

←VE¡Ẋ-

Provalo online!

Spiegazione

   ¡     Repeatedly apply function, collecting results in a list
    Ẋ-     Differences
 VE      Get the index of the first place in the list where all the elements are equal
←        Decrement

2
Ogni volta che qualcuno diceva che Husk è la nuova Jelly, avevano ragione. > _ <
Zacharý

Accidenti, stavo per pubblicare questo . Ottimo lavoro, +1!
Leone,

@Leo, test case che non ho visto [1,1,1,1], posso usare il tuo?
H.Piz,

@HPWiz certo, dai!
Leone,

7

JavaScript (ES6), 47 byte

f=a=>-a.every(x=>i=!x)||1+f(a.map(n=>n-a[++i]))

Casi test


7

MATL , 8 byte

`dta}x@q

Provalo online! Oppure verifica tutti i casi di test .

Spiegazione

Ciò conta ripetutamente le differenze consecutive fino a quando il risultato è tutto zero o vuoto. L'output è il numero richiesto di iterazioni meno 1.

`      % Do... while
  d    %   Consecutive diffferences. Takes input (implicitly) the first time
  t    %   Duplicate
  a    %   True if any element is nonzero. This is the loop condition
}      % Finally (execute before exiting the loop)
  x    %   Delete. This removes the array of all zeros
  @    %   Push iteration index
  q    %   Subtract 1. Implicitly display
       % End (implicit). Proceed with next iteration if top of the stack is true

7

R , 50 44 byte

function(l){while(any(l<-diff(l)))F=F+1
F*1}

Provalo online!

Prende un diffdi l, insiemi esso a l, e controlla se il risultato contiene eventuali valori diversi da zero. Se lo fa, incremento F(inizializzato come FALSEimplicitamente), e ritorna F*1per convertire FALSEa 0nel caso in cui tutti lè identica già.


Programma completo e +Ftrucco per 5 byte . Risposta chiara tra l'altro!
JayCe,

5

Mathematica, 49 byte

(s=#;t=0;While[!SameQ@@s,s=Differences@s;t++];t)&  

grazie a @alephalpa per -6 byte e @hftf -1 byte

ed ecco un altro approccio da @hftf

Mathematica, 49 byte

Length@NestWhileList[Differences,#,!SameQ@@#&]-1&

(s=#;t=0;While[UnsameQ@@s,s=Differences@s;t++];t)&
alephalpha,

1
UnsameQ[1,2,1]è falso; !SameQ[1,2,1]è vero. Non credo che il ciclo manuale salva caratteri sia: Length@NestWhileList[Differences,#,!SameQ@@#&]-1&è già la stessa lunghezza ai suoi dopo la sostituzione UnsameQcon !SameQ.
hftf,


4

Japt , 10 7 byte

è@=ä-)d

Provalo online!

Si basa sul fatto che il risultato è garantito entro la lunghezza dell'array di input.

Spiegazione

è@=ä-)d     Implcit input of array U
 @          For each value in U...
  =ä-)      Update U to be equal to its subsections, each reduced by subtraction
      d     Check if any values in that are truthy
è           Count how many items in that mapping are true

Alla fine, questo mapperà l'array
[1, 3, 9, 26, 66, 150, 313, 610]su [true, true, true, true, true, true, false, false],
che contiene6 true s.

Versione precedente a 10 byte

@=ä-)e¥0}a

Provalo online!


4

Perl 6 , 37 byte

{($_,{@(.[] Z- .[1..*])}...*.none)-2}

Provalo online!

Spiegazione: La funzione accetta l'input come un elenco. Crea quindi una sequenza ricorsiva come questa: il primo elemento è l'elenco originale ( $_), gli elementi successivi vengono restituiti {@(@$_ Z- .[1..*])}chiamando sull'elemento precedente e viene ripetuto fino alla condizione*.none è vera, cosa che accade solo quando l'elenco è vuoto o contiene solo zeri (o, tecnicamente, altri valori di falsità). Quindi prendiamo la lista e sottraggiamo 2 da essa, che la forza prima nel contesto numerico (e le liste in contesto numerico sono uguali al numero dei loro elementi) e, alla fine, restituisce 2 in meno del numero di elementi nella elenco.

Il bizzarro blocco {@(@$_ Z- .[1..*])}prende semplicemente l'elenco dato ( .[]- il cosiddetto slice Zen - l'indicizzazione con parentesi vuote produce l'intero elenco), lo zip usando l'operatore meno ( Z-) con lo stesso elenco senza il primo elemento ( .[1..*]) e lo forza in un elenco ( @(...)- ne abbiamo bisogno perché zip restituisce solo un Seq, che in pratica è un elenco unidirezionale che può essere ripetuto una sola volta. Il che è qualcosa che non ci piace.)


La modifica @(.[] Z- .[1..*])in [.[] Z-.[1..*]]dovrebbe salvare due byte.
nwellnhof,

4

Java 8, 191 + 58 = 249 198 140 byte.

Grazie PunPun1000 per 51 byte.
Grazie Nevay per 58 byte.

int f(int[]a){int x=a.length-1,b[]=new int[x];for(;x-->0;)b[x]=a[x+1]-a[x];return java.util.Arrays.stream(a).distinct().count()<2?0:1+f(b);}

Provalo online!

Provalo online (versione 198 byte)

Quindi, questa è la prima volta che scrivo qui in PPCG (e la prima volta in assoluto a fare una sfida al codice golf). Ogni critica costruttiva è benvenuta e apprezzata. Ho cercato di seguire le linee guida per la pubblicazione, se qualcosa non va, sentitevi liberi di segnalarlo.

Versione abbellita:

int f(int[] a) {
    int x = a.length - 1, b[] = new int[x];
    for (; x-- > 0;) {
        b[x] = a[x + 1] - a[x];
    }
    return java.util.Arrays.stream(a).distinct().count() < 2 ? 0 : 1 + f(b);
}

3
Benvenuti nel sito!
DJMcMayhem

Invece di importare quei moduli puoi semplicemente usarejava.util.stream.IntStream k = java.util.Arrays.stream(a);
PunPun1000 il

In effetti, ci sono un paio di modifiche che puoi apportare gratuitamente. 1) publicnon deve essere incluso nel conteggio dei byte. 2) Non dovresti accettare un secondo parametro, ma rimuoverlo può effettivamente salvare byte. 3) puoi rimuovere alcune parentesi non necessarie lì
PunPun1000

4) Non un risparmiatore ma dovresti includere un TIO se possibile, ecco un esempio con quei suggerimenti a 198 byte TIO
PunPun1000


3

Haskell, 46 byte

g l|all(==l!!0)l=0|0<1=1+g(zipWith(-)l$tail l)

questo semplicemente recluta - zipWith(-)l$last lè l'elenco delle differenze di l. ed gè la funzione che risponde alla domanda.


la soluzione ricorsiva era quella buona.
jferard,

@Jferard è vero
orgoglioso haskeller il

3

Kotlin , 77 byte

primo post, ho provato a modificare l'ultima risposta su kotlin 2 volte; D

{var z=it;while(z.any{it!=z[0]})z=z.zip(z.drop(1),{a,b->a-b});it.size-z.size}

ha partecipato al test da @jrtapsell

TryItOnline


Benvenuti in PPCG! Bella prima risposta, anche un outgolf.
H.Piz

3

APL (Dyalog Classic) , 22 17 byte

{1=≢∪⍵:01+∇2-/⍵}

Provalo online!

Grazie a @ngn per -5 byte!

Come?

  • { ... }, la funzione
  • 1=≢∪⍵:0, se ogni elemento è uguale nell'argomento, restituire 0
  • 1+∇2-/⍵, altrimenti, restituisce 1 + ndelle differenze (che è n-1, quindi aggiungerne una ad essa n)

è più breve se sacrifichi la ricorsività della coda:{1=≢∪⍵:0⋄1+∇2-/⍵}
ngn,

2

Gelatina , 7 byte

IÐĿEÐḟL

Provalo online!

Spiegazione

IÐĿEÐḟL  Main link
 ÐĿ      While results are unique (which is never so it stops at [])
I        Take the increments, collecting intermediate values # this computes all n-th differences
    Ðḟ   Filter out
   E     Lists that have all values equal (the first n-th difference list that is all equal will be removed and all difference lists after will be all 0s)
      L  Take the length (this is the number of iterations required before the differences become equal)

-1 byte grazie a Jonathan Allan


1
@Gryphon Done! :)
HyperNeutrino,

IÐĿEÐḟLper sette (vedo che Miles ha anche trovato un sette usando la ricorsione).
Jonathan Allan,

@JonathanAllan Cool grazie!
HyperNeutrino,

2

05AB1E , 7 byte

[DË#¥]N

Provalo online!

Spiegazione

[         # start loop
 D        # duplicate current list
  Ë       # are all elements equal?
   #      # if so, break
    ¥     # calculate delta's
     ]    # end loop
      N   # push iteration counter

2

JavaScript (ES6), 58 byte

f=a=>+(b=a.slice(1).map((e,i)=>e-a[i])).some(e=>e)&&1+f(b)

+0, non abbastanza Jquery: p. Davvero, +1, bel lavoro, so che non sarei mai stato in grado di giocare a golf in JS.
Zacharý,

2

Python 2 , 65 byte

-7 byte grazie a Jonathan Allan.

f=lambda l,c=1:any(l)and f([j-i for i,j in zip(l,l[1:])],c-1)or-c

Provalo online!


Salvare un byte inizializzazione ca 1, decremento e quindi utilizzando print-c.
Jonathan Allan,

Risparmia altri sei trasformandolo in una funzione ricorsiva:f=lambda l,c=1:any(l)and f([j-i for i,j in zip(l,l[1:])],c-1)or-c
Jonathan Allan,

Sono solo io o il passaggio a una lambda ricorsiva non sta salvando abbastanza byte? : P Grazie!
totalmente umano il

Penso che questo abbia bisogno max(...,0)di superare i [1, 1, 1, 1, ...]casi di test.
Yonatan N,

2

Dyalog APL, 19 byte

≢-1+(≢2-/⍣{1=≢∪⍵}⊢)

Spiegazione:

≢                      length of input
 -1+(             )    minus 1+
     ≢                 length of
      2-/              differences between elements
         ⍣             while
          {1=≢∪⍵}      there is more than 1 unique element
                 ⊢     starting with the input

1
funziona? ≢-1+∘≢2-/⍣{1=≢∪⍵}⊢
Zacharý,

2

k , 21 byte

#1_(~&/1_=':)(1_-':)\

Funziona in k, ma non in oK, perché il ciclo while di oK viene eseguito prima di controllare la condizione (invece di verificare prima la condizione e quindi eseguire il codice). Pertanto, in OK, l' 1 1 1 1 1esempio non funzionerà correttamente.

Prova oK online!

Running the k example with 1 1 1 1 1 1 in the k interpreter.

Spiegazione:

   (        )       \ /while(
    ~&/               /      not(min(
       1_=':          /              check equality of all pairs))) {
             (1_-':)  /    generate difference list
                      /    append to output }
#1_                   /(length of output) - 1

~&/1_=':->1<#?
ngn,

2

Haskell , 66 61 60 byte

z=(=<<tail).zipWith
f=length.takeWhile(or.z(/=)).iterate(z(-))

Provalo online!

5 byte salvati grazie a Christian Sievers

Salvato 1 byte grazie a proud-haskeller

iterate(z(-)) calcola gli elenchi delle differenze.

or.z(/=) verifica se ci sono elementi non uguali in tali elenchi.

length.takeWhile conta le liste delle differenze con elementi non uguali.


Penso che puoi testare elementi non uguali conor.z(/=)
Christian Sievers,

@ChristianSievers grazie! Era ovvio, ma non l'ho visto ...
jferard,

Puoi anche usare z=(=<<tail).zipWithun byte più corto
orgoglioso haskeller il

@proudhaskeller e più elegante, come sempre con definizioni senza punti. Grazie!
jferard,


2

Japt , 7 byte

Stesso approccio (ma derivato indipendentemente) di Justin con un'implementazione diversa.

£=äaÃèx

Provalo


Spiegazione

Input implicito di array U.

£   Ã

Mappa su ogni elemento.

äa

Prendi ogni coppia sequenziale ( ä) di elementi Ue riducila di differenza assoluta ( a).

=

Riassegna quell'array a U.

èx

Count (è) the number of sub-arrays that return truthy (i.e., non-zero) when reduced by addition.


1

TI-Basic, 19 bytes

While max(abs(ΔList(Ans
ΔList(Ans
IS>(A,9
End
A

By default, variables start at zero. Also, never thought I'd be using IS>( for anything useful.


1

C# (.NET Core), 70 69 + 18 bytes

-1 byte thanks to Kevin Cruijssen

g=a=>i=>a.Distinct().Count()>1?g(a.Zip(a.Skip(1),(y,z)=>y-z))(i+1):i;

Must be given 0 when calling to operate correctly. Also included in byte count:

using System.Linq;

Try it online!

Explanation:

g = a => i =>                      // Function taking two arguments (collection of ints and an int)
    a.Distinct()                   // Filter to unique elements
    .Count() > 1 ?                 // If there's more than one element
        g(                         //     Then recursively call the function with
            a.Zip(                 //     Take the collection and perform an action on corresponding elements with another one
                a.Skip(1),         //         Take our collection starting at second element
                (y, z) => y - z    //         Perform the subtraction
            )
        )(i + 1)                   //     With added counter
        : i;                       // Otherwise return counter

Iterative version 84 + 18 bytes:

a=>{int i=0;for(;a.Distinct().Count()>1;i++)a=a.Zip(a.Skip(1),(y,z)=>y-z);return i;}

Try it online!


1
You can remove the redundant space at (y,z)=>y-z. But nice answer, +1 from me.
Kevin Cruijssen

@KevinCruijssen thank you! Also, oops.
Grzegorz Puławski

1

Clojure, 62 bytes

#(loop[c % i 0](if(apply = c)i(recur(map -(rest c)c)(inc i))))

Nicely = can take any number of arguments, and a single argument is identical to "itself". (apply = [1 2 3]) gets executed as (= 1 2 3).


Nice, exactly what I was trying to do but I was struggling for a compact pairwise diffs. That's brilliant, I'll have to remember that for the future.
MattPutnam

1

Pyth, 15 bytes

W.E.+Q=.+Q=hZ)Z

Verify all the test cases.

How?

Explanation #1

W.E.+Q=hZ=.+Q)Z   ~ Full program.

W                 ~ While...
 .E.+Q            ~ ... The deltas of Q contain a truthy element.
      =hZ         ~ Increment a variable Z, which has the initial value of 0.
         =        ~ Transform the variable to the result of a function applied to itself...
          .+Q     ~ ... Operate on the current list and deltas.
             )Z   ~ Close the loop and output Z.

-1 byte Wtl{Q=hZ=.+Q)Z
Dave

@Dave Even better: WP{Q=hZ=.+Q)Z. Thanks!
Mr. Xcoder

0

Perl 5, 83 + 1 (-a) = 84 bytes

sub c{$r=0;$r||=$_-$F[0]for@F;$r}for(;c;$i=0){$_-=$F[++$i]for@F;$#F--}say y/ //-$#F

Try it online!

Input as a list of numbers separated by one space.



0

Pyth, 10 bytes

tf!t{.+FQt

If we can index from 1, we can save a byte by removing the leading t.

Try it Online

Explanation

tf!t{.+FQt
 f        T  Find the first (1-indexed) value T...
     .+FQt   ... such that taking the difference T - 1 times...
  !t{        ... gives a set with more than one value in it.
t            0-index.

0

Kotlin, 83 bytes

{var z=it
var c=0
while(z.any{it!=z[0]}){c++
z=(0..z.size-2).map{z[it+1]-z[it]}}
c}

Beautified

{
    // Make input mutable
    var z=it
    // Count for returning
    var c=0
    // While the array is not identical
    while (z.any { it != z[0] }) {
        // Increment count
        c++
        // Update list to differences
        z = (0..z.size-2).map { z[it+1] - z[it] }
    }
    // Return count
    c
}

Test

var n:(List<Int>)->Int =
{var z=it
var c=0
while(z.any{it!=z[0]}){c++
z=(0..z.size-2).map{z[it+1]-z[it]}}
c}

data class TestData(var input: List<Int>, var output: Int)

fun main(args: Array<String>) {
    val items = listOf(
        TestData(listOf(1,2,3,4,5,6,7,8,9,10), 1),
        TestData(listOf(1,4,9,16,25,36), 2),
        TestData(listOf(1,2,1), 2),
        TestData(listOf(1,1,1,1,1,1,1,1,1), 0),
        TestData(listOf(1, 3, 9, 26, 66, 150, 313, 610), 6)
    )

    val fails = items.map { it to n(it.input) }.filter { it.first.output != it.second }

    if (fails.isEmpty()) {
        println("Test passed")
    } else {
        fails.forEach {println("FAILED: $it")}
    }
}

TryItOnline


If someone could edit to fix my language hints please, I can't seem to get them working
jrtapsell

It's lang-kotlin, not simply kotlin, in the highlighter hints.
Ruslan

0

Swift 4, 90 bytes

func f(_ a:[Int])->Int{return a.contains{$0 != a[0]} ?f(zip(a, a.dropFirst()).map(-))+1:0}

Alternative, closure-based implementation:

var f: ((_ input: [Int]) -> Int)!
f = {a in a.contains{$0 != a[0]} ?f(zip(a, a.dropFirst()).map(-))+1:0}

test cases:

let testcases: [(input: [Int], expected: Int)] = [
    (input: [1,2,3,4,5,6,7,8,9,10],           expected: 1),
    (input: [1,4,9,16,25,36],                 expected: 2),
    (input: [1,2,1],                          expected: 2),
    (input: [1,1,1,1,1,1,1,1,1],              expected: 0),
    (input: [1, 3, 9, 26, 66, 150, 313, 610], expected: 6),
]

for (caseNumber, testcase) in testcases.enumerated() {
    let actual = f(testcase.input)
    assert(actual == testcase.expected,
        "Testcase #\(caseNumber) \(testcase.input) failed. Got \(actual), but expected \(testcase.expected)!")
    print("Testcase #\(caseNumber) passed!")
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.