Suma móvil circular


24

Inspirado por una pregunta en Stack Overflow .

Dada una matriz no xentera de enteros y un entero positivo n, calcule la suma de cada bloque deslizante de longitud a lo nlargo de la matriz x, llenando circularmente los valores faltantes a la izquierda con los valores de la derecha de la siguiente manera:

  • el primer bloque contiene la primera entrada de x, precedida por n-1entradas desplazadas circularmente;
  • el segundo bloque tiene las entradas primera y segunda x, precedidas por n-2entradas desplazadas circularmente; y así.

La matriz de salida ytiene el mismo tamaño que x. Es posible nexceder la longitud de x, y luego los valores de xse reutilizan circularmente varias veces .

Ejemplos

Ejemplo 1 (los valores se reutilizan solo una vez)

x = [2, 4, -3, 0, -4]
n = 3

dar como salida

y = [-2, 2, 3, 1, -7]

dónde

  • -2es la suma del bloque [0, -4, 2](los dos primeros valores provienen del desplazamiento circular)
  • 2es la suma de [-4, 2, 4](el primer valor proviene del desplazamiento circular)
  • 3es la suma de [2, 4, -3](ya no es necesario un desplazamiento circular)
  • 1 es la suma de [4, -3, 0]
  • -7es la suma de [-3, 0, -4].

Ejemplo 2 (los valores se reutilizan varias veces)

x = [1, 2]
n = 5

dar

y = [7, 8]

dónde

  • 7es la suma del bloque [1, 2, 1, 2, 1](los primeros cuatro valores se han reutilizado circularmente)
  • 8es la suma del bloque [2, 1, 2, 1, 2](los primeros tres valores se han reutilizado circularmente)

Reglas adicionales

  • El algoritmo debería funcionar para matrices de tamaño arbitrario y para valores enteros arbitrarios. Es aceptable si el programa está limitado por el tipo de datos o las restricciones de memoria; pero se deben manejar los valores enteros positivos y negativos.
  • La entrada / salida se puede tomar / producir por cualquier medio razonable .
  • Se permiten programas o funciones , en cualquier lenguaje de programación . Las lagunas estándar están prohibidas.
  • El código más corto en bytes gana.

Casos de prueba

x, n, -> y

[2, 4, -3, 0, -4], 3          ->  [-2, 2, 3, 1, -7]
[1, 2], 5                     ->  [7, 8]
[2], 7                        ->  [14]
[-5, 4, 0, 1, 0, -10, -4], 4  ->  [-19, -15, -5, 0, 5, -9, -13]
[-5, 4, 0, 1, 0, -10, -4], 1  ->  [-5, 4, 0, 1, 0, -10, -4]
[-2, -1, 0, 1, 2, 3], 5       ->  [4, 3, 2, 1, 0, 5]
[-10, 0, 10], 4               ->  [-10, 0, 10]

66
Bah, ¿por qué tuviste que usar entradas anteriores?
Neil

Respuestas:


3

Jalea , 5 bytes

ṙC€}S

Pruébalo en línea!

Cómo funciona

ṙC€}S  Main link. Arguments: A (array), n (positive integer)

   }   Apply the link to the left to the right argument (n).
 C€      Complement each; map (z -> 1-z) over [1, ..., n], yielding [0, ..., 1-n].
ṙ      Rotate A 0, ..., 1-n units to the left (i.e., 0, ..., n-1 units to the
       right), yielding a 2D array.
    S  Take the sum of the rows.

7

MATL, 11 10 9 7 bytes

¡3 bytes guardados gracias a @Luis!

:gyn&Z+

La primera entrada es el tamaño de la ventana y la segunda entrada es la matriz

Pruébalo en MATL Online

Explicación

       % Implicitly grab the first input (n)
       %     STACK: { 3 }
:      % Create the array [1...n]
       %     STACK: { [1, 2, 3] }
g      % Convert it to a logical array, yielding an array of 1's of length n
       %     STACK: { [1, 1, 1] }
y      % Implicitly grab the second input and duplicate it
       %     STACK: { [2, 4, -3, 0, -4], [1, 1, 1], [2, 4, -3, 0, -4]}
n      % Determine the length of the array
       %     STACK: { [2, 4, -3, 0, -4], [1, 1, 1], 5}
&Z+    % Perform circular convolution
       %     STACK: { [-2, 2, 3, 1, -7] }
       % Implicitly display the result

6

Mathematica, 29 bytes

RotateLeft[#,1-n]~Sum~{n,#2}&

O la misma longitud:

ListConvolve[1~Table~#2,#,1]&

6

CJam (16 bytes)

{_2$*ew1fb\,~)>}

Conjunto de pruebas en línea . Este es un bloque anónimo (función) que toma la matriz y la longitud en la pila y deja una matriz en la pila.

Disección

{       e# Declare a block
  _2$*  e#   Repeat the array n times: this guarantees having enough windows even
        e#   if x is only a single element
  ew    e#   Take each window of n elements
  1fb   e#   Sum each of the windows
  \,~)  e#   Compute -n
  >     e#   Take the last n elements of the array of sums
}

4

Haskell, 57 bytes

a#n|l<-length a=[sum[a!!mod j l|j<-[i-n..i-1]]|i<-[1..l]]

Pruébalo en línea!

Solo un poco de bucle de índice y acceso a la lista de entrada en los módulos modulan la longitud de la lista.


3

Haskell , 69 65 64 bytes

r=reverse
s#n=r$init[sum$take n$x++cycle(r s)|x<-scanr(:)[]$r s]

Pruébalo en línea! Ejemplo de uso: [2, 4, -3, 0, -4] # 3.


El uso de entradas n exitosas en lugar de las anteriores podría ser 50 46 bytes (deshacerse del reverso al principio y al final):

s#n=init[sum$take n$x++cycle s|x<-scanr(:)[]s]

Pruébalo en línea!



2

Pyth , 18 16 bytes

¡ Ahorré 2 bytes gracias a @FryAmTheEggman !

JEms<.>*JQ-JhdJl

Pruébelo aquí o verifique todos los casos de prueba.

¡Se corrigieron todos los defectos a un costo de -6 bytes ! Muchas gracias a Luis por hacerme entender la tarea en el chat.


Explicación (por actualizar)

KEms<>_*QhK-lQhdKU - Full program.

KE                 - Assign the second input to a variable K.
  m              U - Map over the range [0...len(first input)).
       *QhK        - First input * (Second input + 1).
      _            - Reverse.
     >     -lQhd   - All the elements of the above after len(x)-current element-1
    <          K   - Up until the second input.
   s               - Sum.

Podría ser una mejor manera antes de dar marcha atrás, tratando de jugar al golf pronto.
Sr. Xcoder

Obtuve 16 bytes pero siento que todavía debería haber algo más corto.
FryAmTheEggman

@FryAmTheEggman Gracias. Siento que debería ser más corto, pero no puedo entender cómo
Sr. Xcoder

2

Java 8, 102 bytes

Lambda (al curry) de int[]a lambda de Integera int[]. Asignar a Function<int[], Function<Integer, int[]>>.

a->n->{int l=a.length,o[]=new int[l],i=0,j;for(;i<l;i++)for(j=i-n;j++<i;)o[i]+=a[(j%l+l)%l];return o;}

Pruébalo en línea

Lambda sin golf

a ->
    n -> {
        int
            l = a.length,
            o[] = new int[l],
            i = 0,
            j
        ;
        for (; i < l; i++)
            for (j = i - n; j++ < i; )
                o[i] += a[(j % l + l) % l];
        return o;
    }

(j % l + l) % lcalcula un resto no negativo para cualquiera j. Tomado de aquí .



2

Octava, 53 bytes

@(x,n)shift(imfilter(x,+!!(1:n),'circular'),fix(n/2))

Pruébalo en línea!

  • La imfilterfunción con la opción circularcalcula la convolución circular en el centro de la ventana, por lo que el resultado debe desplazarse.

2

05AB1E , 10 bytes

.׌ùOR¹g£R

Pruébalo en línea!

Explicación

.×           # repeat input_1 input_2 times
  Ν         # push all sublists of size input_2
    O        # sum each
     R       # reverse the list
      ¹g£    # take the first len(input_1) items
         R   # reverse the list

2

Perl 6 , 42 39 bytes

{@^a;[«+»] map {@a.rotate(-$_)},^$^b}

Pruébalo en línea!

Mi primera entrada de Perl 6. Probablemente se puede mejorar.


Tenga en cuenta que a veces puede reducir la longitud utilizando un bloque puntiagudo con variables sin sigilo en lugar de un bloque con parámetros de marcador de posición. ->\a,\b{[«+»] map {a.rotate(-$_)},^b}Tenga en cuenta que no lo hace en este caso, pero lo haría si hubiera otra instancia $ben el código.
Brad Gilbert b2gills

2

Kotlin , 141 140 138 bytes

Solo un primer intento

Sumisión

fun c(a:List<Int>,n:Int):List<Int>{
return (0..(a.size-1)).map{var t=0
for (o in 0..(n-1)){var i=it-o
while(i<0) {i+=a.size};t+=a[i]}
t}}

Embellecido

fun c(a: List<Int>, n: Int): List<Int> {
    return (0..(a.size - 1)).map {    // Iterate over the items
        var t = 0                     // Start the total at 0
        for (o in 0..(n - 1)) {       // Start at the item, go over the window backwards
            var i = it - o            // -------------------------
            while (i < 0) {           //  Make the index in range
                i += a.size           //
            }                         // -------------------------
            t += a[i]                 // Add the item to the total
        }
        t                             // Return the total
    }
}

TryItOnline

Ediciones

  • Nueva línea eliminada antes del último soporte de cierre

1

Röda , 52 bytes

f a,n{(a*n)|slide n|tail#a*n|{head n|sum}while open}

Pruébalo en línea!

Explicación:

f a,n{
  (a*n)|    /* Push the items in a n times to the stream */
  slide n|  /* Create a sliding block of length n */
  tail#a*n| /* Push the last n*len(a) values in the stream to the stream */
  {         /* While there are elements in the stream (stream is open): */
    head n| /*   Pull n values from the stream */
    sum     /*   Sum them and push the sum to the stream */
  } while open
}

1

JavaScript ES6 80 78 bytes

x=>n=>x.map((_,i)=>eval('for(L=x.length,N=0,j=++i-n;j<i;j++)N+=x[(j%L+L)%L]'))

2 bytes guardados gracias a Neil

Uso:

f=x=>n=>x.map((_,i)=>eval('for(L=x.length,N=0,j=++i-n;j<i;j++)N+=x[(j%L+L)%L]'))

f([2, 4, -3, 0, -4])(3)

1
El ,Naspecto es innecesario para mí ...
Neil

@Neil Tienes razón, gracias
Bálint


1

Python 2 , 69 61 bytes

- 8 bytes Muchas gracias @muru

lambda x,n:[sum((x[-n+1:]+x*n)[i:i+n])for i in range(len(x))]

Pruébalo en línea!

Explicación:

Primero debemos asegurarnos de que haya suficientes números a la izquierda de la lista original, esto se logra por x*n+xparte.

Por ejemplo [2,4,-3,0,4],5:

                   ,2,4,-3,0,-4
 ....-4,2,4,-3,0,-4,2,4,-3,0,-4

Luego revertiremos la lista:

 <original->
 -4,0,-3,4,2, -4,0,-3, 4........
           <-2's block->     

A continuación obtenemos los bloques correspondientes para cada elemento por [len(x)+~i:][:n]. El segmento será inverso, es decir, 2 ganará un bloque: [2,-4,0,-3,4]que es inverso al esperado [4,-3,0,-4,2], pero necesitamos la suma después de todo. Entonces, esto funciona. :)


¿No estás seguro de por qué tienes que revertir primero? ¿No puedes modificar los cortes más adelante en la dirección inversa?
Sr. Xcoder

@ Mr.Xcoder Creo que hay una manera, pero esta manera fue menos tediosa, así que me quedé con esto ...: D
officialaimm

1
Creo que x[-n+1:]+x*ndebería darle la lista con suficiente relleno a cada lado, sin tener que invertir ( lambda x,n:[sum((x[-n+1:]+x*n)[i:i+n])for i in range(len(x))])
muru

1
@muru ¿Lo acabas de editar? Ahora funciona. ¡Muchas gracias!
officialaimm


1

K (oK) , 18 bytes

Solución:

{+/+y':(1-y+#x)#x}

Pruébalo en línea!

Ejemplos:

{+/+y':(1-y+#x)#x}[1 2;5]
7 8
{+/+y':(1-y+#x)#x}[-5 4 0 1 0 -10 -4;4]
-19 -15 -5 0 5 -9 -13
{+/+y':(1-y+#x)#x}[-10 0 10;4]
-10 0 10

Explicación:

Estaba a punto de publicar un 31 bytes solución entonces recordé que oK tiene un built-in para las ventanas correderas ...

{+/+y':(1-y+#x)#x} / the solution
{                } / lambda with implicit x and y parameters
               #x  / take (#) from list x
       (    #x)    / length of x
          y+       / add y (window size)
        1-         / subtract from 1 to give a negative
    y':            / sliding window of size y
   +               / flip
 +/                / sum

Prima:

La solución de 31 bytes que también funciona en K4 :

q)k){+/+x#y#'|+(:':\|(1-y+x:#x)#x)}[2 4 -3 0 -4;3]
-2 2 3 1 -7
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.