Ordenar mínimamente una lista en una matriz


18

Dada una lista sin clasificar de enteros únicos estrictamente positivos, ordénelo mínimamente en una matriz 2D. Se garantiza que la lista de entrada tendrá una longitud compuesta, lo que significa que la matriz de salida no es necesariamente cuadrada, sino que tiene un tamaño n x mcon n,m > 1.

"Ordenar mínimamente" aquí significa lo siguiente:

  • Ordenar la lista en orden ascendente.
  • Compactar la matriz de salida tanto como sea posible - a minimizar la suma de las dimensiones de la matriz (por ejemplo, para 20elementos de entrada como entrada, una 5x4o 4x5se requiere matriz de salida, y no una 2x10).
  • Compacte los números ordenados tan lejos como sea posible en la esquina superior izquierda de la matriz, comenzando con el primer elemento en la lista ordenada.
  • Puede pensarse en esto como ordenar la lista, luego cortarla a lo largo de las antiagoniales de la matriz, comenzando por la esquina superior izquierda.

Ejemplos:

Para la entrada, la 1..20salida es una matriz de 5x4 o 4x5 de la siguiente manera:

 1  2  4  7 11
 3  5  8 12 15
 6  9 13 16 18
10 14 17 19 20

 1  2  4  7
 3  5  8 11
 6  9 12 15
10 13 16 18
14 17 19 20

Para la [3, 5, 12, 9, 6, 11]salida de entrada es un 2x3 o 3x2 de la siguiente manera

3  5  9
6 11 12

 3  5
 6  9
11 12

Para la entrada [14, 20, 200, 33, 12, 1, 7, 99, 58], la salida es un 3x3 de la siguiente manera

 1   7  14
12  20  58
33  99 200

Para la entrada, 1..10la salida debe ser 2x5 o 5x2 de la siguiente manera

1 2 4 6  8
3 5 7 9 10

1  2
3  4
5  6
7  8
9 10

Para la [5, 9, 33, 65, 12, 7, 80, 42, 48, 30, 11, 57, 69, 92, 91]salida de entrada es un 5x3 o 3x5 de la siguiente manera

 5  7 11 33 57
 9 12 42 65 80
30 48 69 91 92

 5  7 11
 9 12 33
30 42 57
48 65 80
69 91 92

Reglas

  • Se puede suponer que la entrada se ajusta al tipo de entero nativo de su idioma.
  • La entrada y salida se pueden dar por cualquier método conveniente .
  • Un programa completo o una función son aceptables. Si es una función, puede devolver el resultado en lugar de imprimirlo.
  • Las lagunas estándar están prohibidas.
  • Este es el por lo que se aplican todas las reglas habituales de golf, y gana el código más corto (en bytes).

1
Oh, wow, una palabra que no he visto desde Álgebra Lineal; Fácilmente pasado por alto. Mis disculpas.
Urna mágica del pulpo

@LuisMendo Se agregó un 15caso de prueba de elemento.
AdmBorkBork

Respuestas:


10

Jalea , 24 22 20 bytes

pS€ỤỤs
LÆDżṚ$SÞḢç/ịṢ

Pruébalo en línea!

Guardado 2 bytes gracias a @ Jonathan Allan .

Explicación

pS€ỤỤs  Helper link. Input: integer a (LHS), integer b (RHS)
p       Cartesian product between [1, 2, ..., a] and [1, 2, ..., b]
 S€     Sum each pair
   Ụ    Grade up
    Ụ   Grade up again (Obtains the rank)
     s  Split into slices of length b

LÆDżṚ$SÞḢç/ịṢ  Main link. Input: list A
L              Length
 ÆD            Divisors
     $         Monadic pair
    Ṛ            Reverse
   ż             Interleave
                 Now contains all pairs [a, b] where a*b = len(A)
      SÞ       Sort by sum
        Ḣ      Head (Select the pair with smallest sum)
         ç/    Call helper link
            Ṣ  Sort A
           ị   Index into sorted(A)

L%J¬TżṚ$-> LÆDżṚ$debería salvar a dos, creo
Jonathan Allan

El primer enlace puede convertirse pSÞỤs.
Dennis


4

R 110 95 bytes

function(x){n=sum(x|1)
X=matrix(x,max(which(!n%%1:n^.5)))
X[order(col(X)+row(X))]=sort(x)
t(X)}

Pruébalo en línea!

Cómo funciona

f <- function(x) {
  n <- sum(x|1)                           # length
  p <- max(which(!n%%1:n^.5))             # height of matrix
  X <- matrix(x, p)                       # initialize matrix
  X[order(col(X) + row(X))] <- sort(x)    # filling the matrix using position distance to the top left corner
  t(X)                                    # probably required by OP
}

Giuseppe ahorró la friolera de 15 (!) Bytes con los siguientes trucos

  • reemplazando length(x)por sum(x|1)(-1 byte)
  • floor()no es necesario ya que de :todas formas se redondea hacia abajo (-7)
  • ^.5es más corto que sqrt()(-3)
  • usando en col(X) + row(X)lugar de outer(¡bonito!)
  • sin embargo, no pude deshacerme de eso t(X)- decepcionante;)

Solución original

function(x){
n=length(x)
p=max(which(!n%%1:floor(sqrt(n))))
X=outer(1:p,1:(n/p),`+`)
X[order(X)]=sort(x)
t(X)}

Sería más elegante outerser reemplazado por row(X)+col(X), pero eso requeriría inicializar la matriz de salida Xprimero.

Pruébalo en línea!


2
¡Muy agradable! Puede bajar a 95 bytes
Giuseppe

1
Podría ser capaz de usar algo de mi solución a un desafío relacionado para ayudar aquí también.
Giuseppe

De hecho, está estrechamente relacionado. Muy buen enfoque!
Michael M

3

JavaScript (ES6), 172 bytes

l=>(n=l.sort((a,b)=>b-a).length,w=l.findIndex((_,i)=>!(i*i<n|n%i)),a=l=>[...Array(l)],r=a(n/w).map(_=>a(w)),a(w+n/w).map((_,x)=>r.map((s,y)=>x-y in s&&(s[x-y]=l.pop()))),r)

Explicación

l=>(                                // Take a list l as input
 l.sort((a,b)=>b-a),                // Sort it
 n=l.length,                        // Get the length n
 w=l.findIndex((_,i)=>!(i*i<n|n%i)),// Find the first integer w where w >= √n and n % w = 0
 a=l=>[...Array(l)],                // Helper function a
 r=a(n/w).map(_=>a(w)),             // Create the grid r of size w, n/w
 a(w+n/w).map((_,x)=>               // For every x from 0 to w + n/w:
  r.map((s,y)=>                     //  For every row s in r:
   x-y in s&&(                      //   If the index x-y is in s:
    s[x-y]=l.pop()))),              //    Set s[x-y] to the next element of l
 r)                                 // Return r

Casos de prueba


3

Perl 5 , 132 bytes

sub d{$,=0|sqrt(@_=sort{$a-$b}@_);--$,while@_%$,;map{$r++,$c--for@_/$,..$c;$a[$r++][$c--]=$_;$c=++$i,$r=0if$r<0||$c<0||$r>=$,}@_;@a}

Pruébalo en línea!

La subrutina devuelve una matriz 2-D. El enlace TIO incluye un código de pie de página para mostrar el resultado de la prueba.


3

Octava , 151 bytes

function f(v)n=floor(sqrt(l=nnz(v)));while i=mod(l,n);++n;end;A=nan(m=l/n,n);for k=[1:m 2*m:m:l];do A(k)=sort(v)(++i);until~mod(k+=m-1,m)|k>l;end;A'end

Usando tres tipos diferentes de construcciones de bucle.

Pruébalo en línea!

Desenrollado:

function f(v)
    n = floor(sqrt(l=nnz(v)));

    while i = mod(l,n);
        ++n;
    end;

    A = nan(m=l/n, n);

    for k = [1:m 2*m:m:l];
        do
            A(k) = sort(v)(++i);
        until ~mod(k+=m-1, m) | k>l;
    end;

    A'
end

¡Buena respuesta! ¿Por qué el 'en nnz(v') requiere?
Luis Mendo

1
@LuisMendo ¡Gracias! Resulta que 'no es necesario si envuelvo la expresión de rango, por ejemplo 1:20, alrededor de corchetes ( [1:20]) en el sitio de la llamada (para que sea un vector real). Aparentemente en Octave, el operador de colon no crea un vector , sino una constante de rango que ocupa mucho menos espacio en la memoria. Por alguna razón, nnz()no funciona con ese tipo, pero la transposición de la constante de rango produce un vector, por lo que funciona con el apóstrofe. Llamar a la función con un vector real elimina la necesidad de '.
Steadybox

1
Gracias por la explicación. No sabía que una expresión de rango tenía ese tratamiento especial en Octave. De todos modos, el hecho de que no cree un vector para la eficiencia de la memoria debería ser transparente para el programador. Es decir, el hecho de que nnz(1:20)no funcione es probablemente un error ( max(1:20), sum(1:20)etc. son válidos).
Luis Mendo

1
Deberíamos informarlo . Puede afectar otras funciones que no sean nnz. ¿Quieres hacerlo tú mismo o lo haré?
Luis Mendo

1
Informó . También afectó a MATL; Ahora resuelto . Gracias por notar esto!
Luis Mendo

0

Casco , 15 bytes

ḟȯΛ≤Σ∂MCP¹→←½ḊL

Esto funciona por fuerza bruta, por lo que los casos de prueba más largos pueden expirar. Pruébalo en línea!

Explicación

ḟȯΛ≤Σ∂MCP¹→←½ḊL  Implicit input, a list of integers x.
              L  Length of x (call it n).
             Ḋ   List of divisors.
            ½    Split at the middle.
          →←     Take last element of first part.
                 This is a divisor d that minimizes d + n/d.
        P¹       List of permutations of x.
      MC         Cut each into slices of length d.
ḟ                Find the first of these matrices that satisfies this:
     ∂            Take anti-diagonals,
    Σ             flatten them,
 ȯΛ≤              check that the result is sorted (each adjacent pair is non-decreasing).

0

C (gcc) , 269 bytes

j,w,h,x,y;f(A,l)int*A;{int B[l];for(w=l;w-->1;)for(j=0;j<w;)if(A[j++]>A[j]){h=A[~-j];A[~-j]=A[j];A[j]=h;}for(w=h=j=2;w*h-l;j++)l%j||(w=h,h=j),h*h-l||(w=j);for(x=0;x<w*h;x++)for(y=0;y<=x;y++)x-y<w&y<h&&(B[x-y+y*w]=*A++);for(j=0;j<l;j++)j%w||puts(""),printf("%d ",B[j]);}

Pruébalo en línea!


0

JavaScript (ES6), 233 bytes

f=s=>{l=s.length;i=Math.sqrt(l)|0;for(;l%++i;);p=(x)=>(x/i|0+x%i)*l+x%i;m=[...Array(l).keys()].sort((x,y)=>p(x)-p(y));return s.sort((a,b)=>a-b).map((x,i)=>m.indexOf(i)).reduce((a,b,d,g)=>!(d%i)?a.concat([g.slice(d,d+i)]):a,[])}

Explicación

f=s=>{                         // Take array `s` of numbers as input
  l=s.length                   // short-hand for length
  i=Math.sqrt(l)|0             // = Math.floor(Math.sqrt(l))
  for(;l%++i;);                // i = width           
  j=l/i                        // j = height

  p=(x)=>(x/i|0+x%i)*l+x%i     // helper to calculate (sort-of) ~manhattan
                                 // distance (horizontal distance weighted
                                 // slightly stronger), from top-left corner
                                 // to the number x, if numbers 0,...,l are
                                 // arranged left-to-right, top-to-bottom
                                 // in an l=i*j grid

  m=[...Array(l).keys()]         // range array
  .sort((x,y)=>p(x)-p(y)),       // manhatten-sorted, sort-of...

  return s.sort((a,b)=>a-b)      // sort input array by numbers,
    .map((x,i,w)=>w[m.indexOf(i)])    // then apply inverse permutation of the
                                 // range-grid manhatten-sort mapping.
    .reduce(                     // slice result into rows
      (a,b,d,g)=>!(d%i)?a.concat([g.slice(d,d+i)]):a
      ,[]
     )
}

0

Java 10, 199 188 186 bytes

a->{int j=a.length,m=0,n,i=0,k=0;for(n=m+=Math.sqrt(j);m*n<j;n=j/++m);var R=new int[m][n];for(java.util.Arrays.sort(a);i<m+n;i++)for(j=0;j<=i;j++)if(i-j<n&j<m)R[j][i-j]=a[k++];return R;}

Pruébalo en línea.

Basado en mi respuesta aquí .

Explicación:

a->{                        // Method with int-array parameter and int-matrix return-type
  int j=a.length,           //  Length of the input-array
      m=0,n,                //  Amount of rows and columns
      i=0,k=0;              //  Index integers
   for(n=m+=Math.sqrt(j);   //  Set both `m` and `n` to floor(√ `j`)
       m*n<j;               //  Loop as long as `m` multiplied by `n` is not `j`
       n=j/++m);            //   Increase `m` by 1 first with `++m`
                            //   and then set `n` to `j` integer-divided by this new `m`
   var R=new int[m][n];     //  Result-matrix of size `m` by `n`
   for(java.util.Arrays.sort(a);
                            //  Sort the input-array
       i<m+n;)              //  Loop as long as `i` is smaller than `m+n`
     for(j=0;j<=i;j++)      //   Inner loop `j` in range [0,`i`]
       if(i-j<n&j<m)        //    If `i-j` is smaller than `n`, and `j` smaller than `m`
                            //    (So basically check if they are still within bounds)
         R[j][i-j]=a[k++];  //     Add the number of the input array at index `k`,
                            //     to the matrix in the current cell at `[j,i-j]`
  return R;}                //  Return the result-matrix
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.