Soma circular

24

Inspirado por uma pergunta no Stack Overflow .

Dada uma matriz não vazia de números inteiros xe um número inteiro positivo n, calcule a soma de cada bloco deslizante de comprimento nao longo da matriz x, preenchendo circularmente os valores ausentes à esquerda com valores da direita da seguinte maneira:

  • o primeiro bloco contém a primeira entrada de x, precedida por n-1entradas deslocadas circularmente;
  • o segundo bloco possui a primeira e a segunda entradas de x, precedidas por n-2entradas deslocadas circularmente; e assim por diante.

A matriz de saída ytem o mesmo tamanho que x. É possível nexceder o comprimento de xe, em seguida, os valores de xsão circularmente reutilizados várias vezes .

Exemplos

Exemplo 1 (os valores são reutilizados apenas uma vez)

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

dar como saída

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

Onde

  • -2é a soma do bloco [0, -4, 2](os dois primeiros valores vêm do deslocamento circular)
  • 2é a soma de [-4, 2, 4](o primeiro valor vem do deslocamento circular)
  • 3é a soma de [2, 4, -3](não é mais necessário o deslocamento circular)
  • 1 é a soma de [4, -3, 0]
  • -7é a soma de [-3, 0, -4].

Exemplo 2 (os valores são reutilizados várias vezes)

x = [1, 2]
n = 5

dar

y = [7, 8]

Onde

  • 7é a soma do bloco [1, 2, 1, 2, 1](os quatro primeiros valores foram reutilizados circularmente)
  • 8é a soma do bloco [2, 1, 2, 1, 2](os três primeiros valores foram reutilizados circularmente)

Regras adicionais

  • O algoritmo deve funcionar para matrizes de tamanho arbitrário e para valores inteiros arbitrários. É aceitável se o programa for limitado por tipo de dados ou restrições de memória; mas valores inteiros positivos e negativos devem ser manipulados.
  • A entrada / saída pode ser obtida / produzida por qualquer meio razoável .
  • Programas ou funções são permitidos, em qualquer linguagem de programação . As brechas padrão são proibidas.
  • O menor código em bytes vence.

Casos de teste

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]
Luis Mendo
fonte
6
Bah, por que você teve que usar entradas anteriores?
Neil

Respostas:

3

Geléia , 5 bytes

ṙC€}S

Experimente online!

Como 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.
Dennis
fonte
7

MATL, 11 10 9 7 bytes

3 bytes salvos graças ao @Luis!

:gyn&Z+

A primeira entrada é o tamanho da janela e a segunda entrada é a matriz

Experimente no MATL Online

Explicação

       % 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
Suever
fonte
6

Mathematica, 29 bytes

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

Ou o mesmo comprimento:

ListConvolve[1~Table~#2,#,1]&
alefalpha
fonte
6

CJam (16 bytes)

{_2$*ew1fb\,~)>}

Conjunto de testes online . Este é um bloco anônimo (função) que pega a matriz e o comprimento na pilha e deixa uma matriz na pilha.

Dissecação

{       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
}
Peter Taylor
fonte
4

Haskell, 57 bytes

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

Experimente online!

Apenas alguns índices em loop e acessando a lista de entrada em índices modulam o comprimento da lista.

nimi
fonte
3

Haskell , 69 65 64 bytes

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

Experimente online! Exemplo de utilização: [2, 4, -3, 0, -4] # 3.


O uso de entradas n sucessivas em vez das anteriores pode ser 50 46 bytes (livrar-se do inverso no início e no final):

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

Experimente online!

Laikoni
fonte
2

Pitão , 18 16 bytes

Guardado 2 bytes graças a @FryAmTheEggman !

JEms<.>*JQ-JhdJl

Experimente aqui ou verifique todos os casos de teste.

Corrigido todos os defeitos a um custo de -6 bytes ! Muito obrigado ao Luis por me fazer entender a tarefa no chat.


Explicação (a ser atualizada)

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.
Mr. Xcoder
fonte
Pode ser uma maneira melhor antes de reverter, tentando jogar golfe em breve.
Xcoder
Tenho 16 bytes, mas sinto que ainda deve haver algo mais curto.
FryAmTheEggman
@FryAmTheEggman Thanks. Eu acho que deve ser mais curto, mas não consigo descobrir como é
#
2

Java 8, 102 bytes

Lambda (ao curry) de int[]para lambda de Integerpara int[]. Atribuir 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;}

Experimente Online

Lambda ungolfed

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 um restante não negativo para qualquer j. Tomado daqui .

Jakob
fonte
2

C, 91 bytes

i,j,k,s;f(a,l,n)int*a;{for(i=0;i<l;printf("%d ",s))for(j=n*l+i++,k=n,s=0;k--;)s+=a[j--%l];}

Experimente online!

Steadybox
fonte
2

Oitava, 53 bytes

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

Experimente online!

  • A imfilterfunção com a opção circularcalcula a convolução circular no centro da janela para que o resultado seja alterado.
rahnema1
fonte
2

05AB1E , 10 bytes

.׌ùOR¹g£R

Experimente online!

Explicação

.×           # 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
Emigna
fonte
2

Perl 6 , 42 39 bytes

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

Experimente online!

Minha primeira entrada no Perl 6. Provavelmente pode ser melhorado.

Nwellnhof
fonte
Note que às vezes você pode reduzir o comprimento usando um bloco pontudo com variáveis sigilless em vez de um bloco com parâmetros de espaço reservado ->\a,\b{[«+»] map {a.rotate(-$_)},^b}Note que isso não acontece neste caso, mas que seria se não havia outra instância $bno código.
Brad Gilbert b2gills
2

Kotlin , 141 140 138 bytes

Apenas uma primeira tentativa

Submissão

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

Embelezado

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

Edições

  • Nova linha removida antes do último colchete de fechamento
jrtapsell
fonte
1

Röda , 52 bytes

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

Experimente online!

Explicação:

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
}
fergusq
fonte
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 salvos graças 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)
Bálint
fonte
11
Os ,Nolhares desnecessários para mim ...
Neil
@Neil você está certo, graças
Bálint
1

Python 2 , 69 61 bytes

- 8 bytes Muito obrigado @muru

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

Experimente online!

Explicação:

Primeiro, precisamos garantir que haja números suficientes no lado esquerdo da lista original, isso é obtido pela x*n+xparte.

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

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

Então, reverteremos a lista:

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

Em seguida, obtemos os blocos correspondentes para cada elemento por [len(x)+~i:][:n]. A fatia será inversa, ou seja, 2 ganhará um bloco: [2,-4,0,-3,4]que é o inverso do esperado [4,-3,0,-4,2], mas precisamos da soma, afinal. Então, isso funciona. :)

officialaimm
fonte
Não sabe por que você precisa reverter primeiro? Você não pode modificar as fatias posteriormente na direção inversa?
Xcoder
@ Mr.Xcoder Eu acho que há um caminho, mas este caminho foi menos tedioso para que eu colada com isso ...: D
officialaimm
11
Eu acho que x[-n+1:]+x*ndeve dar-lhe a lista com estofamento suficiente em ambos os lados, sem ter de reverter ( lambda x,n:[sum((x[-n+1:]+x*n)[i:i+n])for i in range(len(x))])
Muru
11
@muru Você acabou de editar? Agora funciona. Muito obrigado!
officialaimm
1

R , 101 93 89 bytes

function(x,n,w=sum(x|1)){for(j in 1:w)F=c(F,sum(c(tail(rep(x,n),n-1),x)[1:n+j-1]))
F[-1]}

Experimente online!

Giuseppe
fonte
1

K (oK) , 18 bytes

Solução:

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

Experimente online!

Exemplos:

{+/+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

Explicação:

Quando estava prestes a publicar uma solução de 31 bytes , lembrei-me de que o oK tem um built-in para janelas deslizantes ...

{+/+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

Bônus:

A solução de 31 bytes que também funciona no K4 :

q)k){+/+x#y#'|+(:':\|(1-y+x:#x)#x)}[2 4 -3 0 -4;3]
-2 2 3 1 -7
rua
fonte