Ziguezague uma matriz

43

Como parte de seu algoritmo de compactação, o padrão JPEG desenrola uma matriz em um vetor ao longo de antidiagonais de direção alternada:

insira a descrição da imagem aqui

Sua tarefa é pegar uma matriz (não necessariamente quadrada) e devolvê-la na forma desenrolada. Como um exemplo:

[1 2 3 4
 5 6 7 8
 9 1 2 3]

deve render

[1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]

Regras

Você pode assumir que os elementos da matriz são números inteiros positivos menores que 10.

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e emitindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

A matriz de entrada pode ser fornecida em qualquer formato conveniente de lista ou string aninhada, inequívoca, ou como uma lista simples, juntamente com as duas dimensões da matriz. (Ou, é claro, como um tipo de matriz, se o seu idioma tiver esse.)

O vetor de saída pode estar em qualquer formato conveniente, inequívoco, de lista simples ou de sequência.

Aplicam-se as regras padrão de .

Casos de teste

[[1]]                                               => [1]
[[1 2] [3 1]]                                       => [1 2 3 1]
[[1 2 3 1]]                                         => [1 2 3 1]
[[1 2 3] [5 6 4] [9 7 8] [1 2 3]]                   => [1 2 5 9 6 3 4 7 1 2 8 3]
[[1 2 3 4] [5 6 7 8] [9 1 2 3]]                     => [1 2 5 9 6 3 4 7 1 2 8 3]
[[1 2 6 3 1 2] [5 9 4 7 8 3]]                       => [1 2 5 9 6 3 4 7 1 2 8 3]
[[1 2 5 9 6 3 4 7 1 2 8 3]]                         => [1 2 5 9 6 3 4 7 1 2 8 3]
[[1] [2] [5] [9] [6] [3] [4] [7] [1] [2] [8] [3]]   => [1 2 5 9 6 3 4 7 1 2 8 3]

Desafios relacionados

Martin Ender
fonte
1
A entrada pode ser uma matriz real em J? Ou precisaria ser transformado de listas aninhadas em uma matriz como parte da função?
Gareth
4
Se tomarmos a matriz como uma matriz 2D, ainda podemos tomar as dimensões como entradas?
Xnor
1
@Gareth sim, você pode usar um tipo de matriz como entrada.
Martin Ender
1
@xnor Hmmm, isso é um pouco mais complicado. Sinto que levar essa quantidade de informações redundantes é um pouco para pré-processar a entrada.
Martin Ender
A lista simples pode estar na ordem das colunas principais, se essa for a ordem nativa do idioma?
18136 Luis Mendo

Respostas:

27

J, 31 30 14 12 11 bytes

[:;<@|.`</.

Ych . Muito grande.

Toma uma matriz como entrada.

Explicação

J tem uma vantagem aqui. Existe um comando chamado oblique ( /.) que pega as linhas oblíquas e aplica um verbo a elas. Neste caso, estou usando um gerúndio para aplicar dois verbos alternadamente: <( caixa ) e <@|.( reverso e caixa). Então é apenas uma questão de desembalar tudo usando ;( raze ).

Gareth
fonte
26
J é o único idioma que me faz sentir que preciso de um diploma avançado em inglês para entendê-lo.
Alex A.
2
@AlexA. btw, a palavra "comando" deveria ter sido "advérbio".
Adám 16/03/16
11

Pitão, 24 23 21 20 19 18 17 bytes

ssm_W=!Td.T+LaYkQ

Versão alternativa de 17 bytes: ssuL_G=!T.T+LaYkQ

                Q  input
           +L      prepend to each subarray...
             aYk   (Y += ''). Y is initialized to [], so this prepends [''] to
                     the first subarray, ['', ''] to the second, etc.
                   ['' 1  2  3  4
                    '' '' 5  6  7  8
                    '' '' '' 9  1  2  3]
         .T        transpose, giving us
                   ['' '' ''
                    1  '' ''
                    2  5  ''
                    3  6  9
                    4  7  1
                    8  2
                    3]
  m_W=!Td          black magic
 s                 join subarrays together
s                  join *everything* on empty string (which means ''s used for
                     padding disappear)

Graças a @FryAmTheEggman por um byte, @Jakube por 2 bytes e @isaacg por um byte!

A explicação da "magia negra" mencionada acima: m_W=!Tdessencialmente inverte todos os outros subarrays. Faz isso mapeando _W=!Tsobre cada sub-matriz; Wé aplicação condicional, portanto, _s (inverte) todos os sub-arranjos onde =!Té verdadeiro. Té uma variável pré-inicializada para dez (verdade) e =!Tmédia (T = !T). Portanto, alterna o valor de uma variável que começa com verdade e retorna o novo valor, o que significa que alternará entre retornar falsy, truthy, falsy, truthy ... (agradece a Jakube por essa ideia)

Conjunto de teste aqui .

Maçaneta da porta
fonte
11

Geléia, 24 19 15 13 11 bytes

pS€żị"¥pỤị⁵

Leva o número de linhas, o número de colunas e uma lista simples como argumentos separados da linha de comando.

Experimente online!

Como funciona

pS€żị"¥pỤị⁵  Main link. Argument: m (rows), n (columns), A (list, flat)

p            Compute the Cartesian product [1, ..., m] × [1, ..., n]. This yields
             the indices of the matrix M, i.e., [[1, 1], [1, 2], ..., [m, n]].
 S€          Compute the sums of all index pairs.
       p     Yield the Cartesian product.
      ¥      Dyadic chain. Arguments: Sums, Cartesian product.
    ị"       For each index pair in the Cartesian product, retrieve the coordinate
             at the index of its sum, i.e., map [i, j] to i if i + j is odd and to
             j if i + j is even.
   ż         Zip the sums with the retrieved indices.
       Ụ     Sort [1, ..., mn] by the corresponding item in the resulting list.
        ị⁵   Retrieve the corresponding items from A.
Dennis
fonte
Tsk. Não tenho certeza se posso diminuir o meu agora. : -S
Gareth
Isso não quer dizer que eu não vou tentar embora ...
Gareth
Por que Jelly ainda não herdou Oblique? Posso sugerir os glifos da APL e ? Ou talvez escandinavo øe ǿ?
Adám 16/03/16
7

MATL , 28 27 bytes

tZyZ}:w:!+-1y^7MGn/*-X:K#S)

Adaptado da minha resposta aqui . A idéia geral é criar uma matriz 2D do mesmo tamanho da entrada, preenchida com valores que aumentam na mesma ordem que o caminho em zig-zag. Em seguida, a versão linearizada (achatada) dessa matriz é classificada e os índices dessa classificação são mantidos. Esses são os índices que precisam ser aplicados à entrada para produzir o caminho em zig-zag.

A entrada está no formato

[1 2 3; 5 6 4; 9 7 8; 1 2 3]

Explicação

Experimente online!

t       % input 2D array. Duplicate
ZyZ}    % get size as length-2 vector. Split into two numbers: r, c
:       % range [1,2,...,c] as a row vector
w:!     % swap, range [1;2;...;r] as a column vector
+       % add with broadcast. Gives a 2D array
-1      % push -1
y^      % duplicate previous 2D array. Compute -1 raised to that
7M      % push [1;2;...;r] again
Gn/     % divide by input matrix size, that is, r*c
*       % multiply
-       % subtract
X:      % linearize 2D array into column array
K#S     % sort and push the indices of the sorting. Gives a column vector
)       % index input matrix with that column vector
Luis Mendo
fonte
4

Matlab, 134 bytes

Eu apenas tentei encurtar meu código no Matlab, como telegrafá-lo.

function V=z(M)
[m,n]=size(M);
a=(1:m)'*ones(1,n);
b=ones(m,1)*(1:n);
A=a+b-1;
B=a-b;
C=(A.^2+(-1).^A.*B+1);
[~,I]=sort(C(:));
V=M(:);
V=V(I)';

Notas:

  1. Mé uma m×nmatriz.
  2. ae bambas são matrizes do mesmo tamanho M, cada linha aconsiste em números iguais ao número da linha, enquanto cada coluna de bé igual ao número da coluna. Assim, a+ bé uma matriz cujo elemento é igual à soma do seu número de linha e coluna, ou seja matrix(p,q)=p+q,.
  3. Assim A(p,q)=p+q-1,; e B(p,q)=p-q.
  4. Cé matematicamente indicado como equação abaixo. Matriz que aumenta em ziguezague com a equação, uma matriz que aumenta em ziguezague pode ser feita como mostrado abaixo.
C =
     1     2     6     7
     3     5     8    14
     4     9    13    18
    10    12    19    25
  1. Cindica a ordem dos elementos de M nos resultados em ziguezague. Então, [~,I]=sort(C(:));retorna a ordem, ou seja I, V=V(I)'é o resultado.
Guoyang Qin
fonte
Sim, acabei de encontrar, agora atualizo.
Guoyang Qin
@AlexA. Obrigado, Alex. Pois sou novo nisso e quero reduzi-lo o mais curto possível, mas torná-lo um trecho. Agora eu corrigi meu código ainda.
Guoyang Qin
Parece bom. Bom primeiro post! :)
Alex A.
3

JavaScript (SpiderMonkey 30+), 99 bytes

x=>[for(y of[...x,...x[0]].keys())for(z of Array(y+1).keys())if(a=x[y%2?z:y-z])if(b=a[y%2?y-z:z])b]

Testado no Firefox 44. Recebe entrada como uma matriz 2D.

ETHproductions
fonte
3

Python 2, 84 bytes

lambda N,w,h:[N[i*w+s-i]for s in range(w+h+1)for i in range(h)[::s%2*2-1]if-1<s-i<w]

Portando a resposta de nimi . Toma uma matriz plana com largura e altura especificadas. O xsot salvou um byte.


88 bytes:

lambda M,w,h:[M[i]for i in sorted(range(w*h),key=lambda i:(i/w+i%w,-i*(-1)**(i/w+i%w)))]

Toma uma matriz plana com largura e altura especificadas. Classifica as coordenadas 2D correspondentes (i/w,i%w)em ordem em zigue-zague de soma crescente para obter diagonais, quebradas pelo valor da linha, aumentando ou diminuindo, com base no fato de a coluna de linha mais ser ímpar ou par.

xnor
fonte
Que se a condição puder ser reduzida ainda mais.
Xsot # 16/16
@xsot Boa captura.
Xnor
3

Haskell, 79 78 73 bytes

(m#h)w=[m!!(y*w+x-y)|x<-[0..h+w],y<-g!!x$[0..x],y<h,x-y<w]
g=reverse:id:g

A entrada é uma lista simples com o número de linhas e colunas, por exemplo ( [1,2,6,3,1,2,5,9,4,7,8,3] # 2) 6- -> [1,2,5,9,6,3,4,7,1,2,8,3].

Como funciona: percorra as coordenadas xey da matriz ( hlinhas, wcolunas) em dois loops aninhados:

  | 0 1 2 3 4 5 6 7 8    outer loop               Index is y*w+x-y, i.e.
--+------------------    x from 0 to h+w          the elements are accessed
0 | 1 2 6 3 1 2                                   in the following order:
1 | 5 9 4 7 8 3
2 |                                               1 2 4 6  8 10 
3 |                                               3 5 7 9 11 12
4 |
5 |
6 |
7 | inner loop:
8 | y from 0 to x

ou seja, de cima / direita para baixo / esquerda, pulando fora dos índices vinculados ( ye xdeve satisfazer y<he x-y<w). Quando xé par, a ordem do loop interno é invertida: ypassa de xpara 0. Eu faço isso escolhendo uma função de modificação para o intervalo y, [0..x]que é o xth elemento de [reverse,id,reverse,id,...].

Edit: @xnor reorganizou os loops e salvou 5 bytes. Obrigado!

nimi
fonte
Eu acho que você pode fazer g=id:reverse:g.
Xnor
Os parênteses na multication (y-x)*wpode ser cortado, transpondo o problema: (m#h)w=[m!!(x*w+y-x)|y<-[0..h+w],x<-g!!y$[0..y],x<h,y-x<w] g=reverse:id:g. A tradução para Python economiza três caracteres sobre o que eu tinha.
Xnor
1

Python 2 + NumPy, 122 bytes

Eu admito. Eu trabalhei à frente. Infelizmente, esse mesmo método não pode ser facilmente modificado para resolver os outros 2 desafios relacionados ...

import numpy
def f(m):w=len(m);print sum([list(m[::-1,:].diagonal(i)[::(i+w+1)%2*-2+1])for i in range(-w,w+len(m[0]))],[])

Toma uma matriz numpy como entrada. Mostra uma lista.

Experimente online

Explicação:

def f(m):
    w=len(m)    # the height of the matrix, (at one point I thought it was the width)
    # get the anti-diagonals of the matrix. Reverse them if odd by mapping odd to -1
    d=[list(m[::-1,:].diagonal(i)[::(i+w+1)%2*-2+1])for i in range(-w,w+len(m[0]))]
            # w+len(m[0]) accounts for the width of the matrix. Works if it's too large.
    print sum(d,[]) # join the lists

Um lambda tem o mesmo comprimento:

import numpy
lambda m:sum([list(m[::-1,:].diagonal(i)[::(i+len(m)+1)%2*-2+1])for i in range(-len(m),len(m)+len(m[0]))],[])
mbomb007
fonte
1

Python 3, 131 118 115 107 107 bytes

Baseado no mesmo princípio da minha resposta ao desafio de Deusovi

Presumo que não podemos ter zero na matriz de entrada

e=enumerate
lambda s:[k for j,i in e(zip(*[([0]*n+i+[0]*len(s))for n,i in e(s)]))for k in i[::j%2*2-1]if k]

Explicação

como funciona :

            pad with 0      transpose    remove 0    reverse line           concatenate 
                                                     with even index
1 2 3       1 2 3 0 0        1 0 0        1            1                
4 5 6   --> 0 4 5 6 0    --> 2 4 0    --> 2 4     -->  2 4              -->  1 2 4 7 5 3 6 8 9
7 8 9       0 0 7 8 9        3 5 7        3 5 7        7 5 3             
                             0 6 8        6 8          6 8               
                             0 0 9        9            9

Resultados

>>> [print([i,f(i)]) for i in [[[1]], [[1, 2], [3, 1]], [[1, 2, 3, 1]], [[1, 2, 3], [5, 6, 4], [9, 7, 8], [1, 2, 3]], [[1, 2, 3, 4], [5, 6, 7, 8], [9, 1, 2, 3]], [[1, 2, 6, 3, 1, 2], [5, 9, 4, 7, 8, 3]], [[1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]], [[1], [2], [5], [9], [6], [3], [4], [7], [1], [2], [8], [3]]]]
# [input,                                                          output]
[[[1]],                                                            [1]]
[[[1, 2], [3, 1]],                                                 [1, 2, 3, 1]]
[[[1, 2, 3, 1]],                                                   [1, 2, 3, 1]]
[[[1, 2, 3], [5, 6, 4], [9, 7, 8], [1, 2, 3]],                     [1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]]
[[[1, 2, 3, 4], [5, 6, 7, 8], [9, 1, 2, 3]],                       [1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]]
[[[1, 2, 6, 3, 1, 2], [5, 9, 4, 7, 8, 3]],                         [1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]]
[[[1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]],                           [1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]]
[[[1], [2], [5], [9], [6], [3], [4], [7], [1], [2], [8], [3]],     [1, 2, 5, 9, 6, 3, 4, 7, 1, 2, 8, 3]]
Erwan
fonte
Em vez disso deveria reverse even lineser reverse odd lines?
nwp 16/03
O índice @nwp começa em 0 ^^
Erwan
Ah, você está falando sobre os números das linhas, não o comprimento da linha. Eu confundi isso, desculpe.
Nwp 16/03
np @nwp, btw eu mudei para confusão evitar
Erwan