リストを最小限の行列に並べ替える


18

一意の厳密に正の整数のソートされていないリストが与えられた場合、最小限で2Dマトリックスにソートします。入力リストは複合長であることが保証されています。つまり、出力行列は必ずしも正方形ではなく、サイズがn x mn,m > 1

ここでの「最小ソート」とは、次のことを意味します。

  • リストを昇順で並べ替えます。
  • 出力行列を可能な限りコンパクトにします-行列の次元の合計を最小化し20ます(たとえば、入力として入力要素の5x4場合、aではなくa または4x5output行列が必要です2x10)。
  • ソートされたリストの最初の要素から始めて、ソートされた数値を可能な限りマトリックスの左上まで圧縮します。
  • これは、リストを並べ替えてから、マトリックスの対角線に沿って左上からスライスすることと考えることができます。

例:

入力の1..20場合、出力は次のように5x4または4x5マトリックスです。

 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

入力の[3, 5, 12, 9, 6, 11]場合、出力は次のように2x3または3x2です

3  5  9
6 11 12

 3  5
 6  9
11 12

入力の[14, 20, 200, 33, 12, 1, 7, 99, 58]場合、出力は次のように3x3です

 1   7  14
12  20  58
33  99 200

入力の場合1..10、出力は次のように2x5または5x2である必要があります

1 2 4 6  8
3 5 7 9 10

1  2
3  4
5  6
7  8
9 10

入力の[5, 9, 33, 65, 12, 7, 80, 42, 48, 30, 11, 57, 69, 92, 91]場合、出力は次のように5x3または3x5です

 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

ルール

  • 入力は、言語のネイティブ整数型に適合すると仮定できます。
  • 入力と出力は、任意の便利な方法で指定できます。
  • 完全なプログラムまたは機能のいずれかが受け入れられます。関数の場合、出力する代わりに出力を返すことができます。
  • 標準的な抜け穴は禁止されています。
  • これはので、通常のゴルフルールがすべて適用され、最短のコード(バイト単位)が勝ちます。

1
ああ、すごい、線形代数以来見たことのない言葉。簡単に見落とされます。謝罪いたします。
魔法のタコ

@LuisMendo 15要素のテストケースを追加しました。
AdmBorkBork

回答:


10

ゼリー24 22 20バイト

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

オンラインでお試しください!

@ Jonathan Allanのおかげで2バイト節約されました。

説明

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żṚ$2つを保存する必要があります
ジョナサンアラン

最初のリンクはになりpSÞỤsます。
デニス


4

R 110 95バイト

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

オンラインでお試しください!

使い方

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
}

ジュゼッペは、次のトリックによってなんと15(!)バイトを節約しました

  • 交換するlength(x)ことにより、sum(x|1)(-1バイト)
  • floor() 必要ありません :とにかく切り捨てん(-7)
  • ^.5sqrt()(-3)より短い
  • 使用してcol(X) + row(X)の代わりに、outer(素敵!)
  • を取り除くことができませんでしたが、t(X)残念です;)

元のソリューション

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

outer置き換えられるとrow(X)+col(X)、もっと派手に見えますが、X最初に出力行列を初期化する必要があります。

オンラインでお試しください!


2
非常に素晴らしい!95バイト
ジュゼッペ

1
私のソリューションから関連する課題への何かをここで役立つように使用できるかもしれません。
ジュゼッペ

それは確かに密接に関連しています。とてもいいアプローチです!
マイケルM

3

JavaScript(ES6)、172バイト

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)

説明

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

テストケース


3

Perl 5、132バイト

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}

オンラインでお試しください!

サブルーチンは2次元配列を返します。TIOリンクには、テスト結果を表示するためのフッターコードが含まれています。


3

オクターブ、151バイト

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

3つの異なる種類のループ構造の使用。

オンラインでお試しください!

展開:

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

いい答え!'nnz(v') 必要なのはなぜですか?
ルイスメンドー

1
@LuisMendoありがとう!'たとえば1:20[1:20]呼び出しサイトで角括弧()の周りに(実際のベクトルにするために)範囲式をラップする場合、は必要ありません。Octaveでは、コロン演算子はvectorを作成しませんが、メモリ内のスペースを大幅に削減する範囲定数を作成します。何らかの理由で、nnz()そのタイプでは機能しませんが、範囲定数を転置するとベクトルが生成されるため、アポストロフィでも機能します。実際のベクトルで関数を呼び出すと、の必要がなくなり'ます。
Steadybox

1
説明してくれてありがとう。Octaveでは、範囲式に特別な扱いがあることを知りませんでした。とにかく、それがメモリ効率のためのベクトルを作成しないという事実は、プログラマーに対して透過的でなければなりません。これは、事実であるnnz(1:20)(仕事はおそらくバグですしないmax(1:20)sum(1:20)などがある有効)。
ルイスメンドー

1
報告する必要があります。以外の機能に影響する可能性がありますnnz。自分でやりたいですか、それとも私ですか?
ルイスメンドー

1
報告済み。また、MATLにも影響しました。今解決しました。これに気づいてくれてありがとう!
ルイスメンドー

0

、15バイト

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

これはブルートフォースで機能するため、テストケースが長くなるとタイムアウトする場合があります。 オンラインでお試しください!

説明

ḟȯΛ≤Σ∂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

JavaScript(ES6)、233バイト

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,[])}

説明

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バイト

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

オンラインでお試しください。

ここでの私の答えに基づきます

説明:

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.