Block-sorting rows and columns in a 2D array

Block-sorting rows and columns in a 2D array



Given a 2D array of integers, let's sort its rows and columns in blocks. This means that you only have to sort a given row or column, but applying the transformations needed for sorting it to every other row or column in the 2D array.


4x3


-2


3


Positive indices for rows and negative indices for columns

[5 8 7 6 [1 3 2 4
1 3 2 4 order by -3 (3rd column) --> 9 6 3 0
9 6 3 0] 5 8 7 6]

[5 8 7 6 [9 6 3 0
1 3 2 4 order by -4 (4th column) --> 1 3 2 4
9 6 3 0] 5 8 7 6]

[5 8 7 6 [5 7 8 6
1 3 2 4 order by 2 (2nd row) --> 1 2 3 4
9 6 3 0] 9 3 6 0]

[5 8 7 6 [6 7 8 5
1 3 2 4 order by 3 (3rd row) --> 4 2 3 1
9 6 3 0] 0 3 6 9]

[1 2 [1 2 [3 2
3 2] order by -2 (2nd column) --> 3 2] or 1 2] (both are valid)

[7 5 9 7 [5 7 7 9 [5 7 7 9
1 3 2 4 order by 1 (1st row) --> 3 1 4 2 or 3 4 1 2
9 6 3 0] 6 9 0 3] 6 0 9 3]



This is code-golf, so may the shortest code for each language win!





$begingroup$
This comes from the sandbox.
$endgroup$
– Charlie
Sep 12 '18 at 13:45





$begingroup$
Can we change the integer representation? negative for rows and positive for columns?
$endgroup$
– Luis felipe De jesus Munoz
Sep 12 '18 at 14:22





$begingroup$
@LuisfelipeDejesusMunoz yes, that is stated in the question.
$endgroup$
– Charlie
Sep 12 '18 at 14:23





$begingroup$
Can a row/column contain duplicated numbers?
$endgroup$
– Kevin Cruijssen
Sep 12 '18 at 15:00





$begingroup$
@KevinCruijssen yes, see last examples and last point of the rules.
$endgroup$
– Charlie
Sep 12 '18 at 15:01





20 Answers
20




R, 55 bytes


function(x,n)`if`(n>0,x[,+x[n,]],x[+x[,-n],])
`+`=order



Try it online!



Reassigns the + operator (actually a function in R) to the order function, which returns the indices of a vector from smallest to largest. Then it's just array manipulation.


+


order





$begingroup$
It's just as short as a recursive function :-)
$endgroup$
– Giuseppe
Sep 12 '18 at 14:52




R, 55 bytes


f=function(m,i)"if"(i<0,t(f(t(m),-i)),m[,order(m[i,])])



Try it online!



Alternative to ngm's answer; a recursive function which was inspired by DimChtz's answer


@(m,i)sortrows(m,-i) sortrows(m',i)'(i>0)+1



Try it Online!



-11 bytes thanks to @Giuseppe.



-15 bytes thanks to @LuisMendo.




Japt, 18 17 bytes



negative for rows and positive for columns


>0?VñgUÉ:ßUa Vy)y



Try it online!





$begingroup$
This fails when U is negative - the previous 17 byte version works, though.
$endgroup$
– Shaggy
Sep 12 '18 at 15:27


U





$begingroup$
@Shaggy My bad, I though it would work anyway, didnt check at all
$endgroup$
– Luis felipe De jesus Munoz
Sep 12 '18 at 15:33





$begingroup$
Not a bad idea, though, passing a function as the first argument of ß that automatically gets applied to U. It could create issues with trying to pass literal strings, but post a suggestion to the GitHub repo anyway for further investigation.
$endgroup$
– Shaggy
Sep 12 '18 at 15:35


ß


U




05AB1E, 25 24 14 bytes


diø}Σ¹Ä<è}¹diø



Whopping -10 bytes thanks to @Emigna.



Uses a positive integer-input to sort the rows, negative for columns.



Try it online or verify all test cases.



Explanation:


di } # If the (implicit) integer input is positive:
ø # Swap the rows and columns of the (implicit) matrix input
# i.e. 3 and [[5,8,7,6],[1,3,2,4],[9,6,3,0]]
# → [[5,1,9],[8,3,6],[7,2,3],[6,4,0]]
Σ } # Sort the rows of this matrix by:
¹Ä # Take the absolute value of the input
# i.e. -3 → 3
< # Decreased by 1 to make it 0-indexed
# i.e. 3 → 2
è # And index it into the current row
# i.e. [5,8,7,6] and 2 → 7
# i.e. [5,1,9] and 2 → 9
# i.e. [[5,1,9],[8,3,6],[7,2,3],[6,4,0]] sorted by [9,6,3,0]
# → [[6,4,0],[7,2,3],[8,3,6],[5,1,9]]
# i.e. [[5,8,7,6],[1,3,2,4],[9,6,3,0]] sorted by [7,2,3]
# → [[1,3,2,4],[9,6,3,0],[5,8,7,6]]
¹di # And if the integer input was positive:
ø # Swap the rows and columns back again now that we've sorted them
# i.e. 3 and [[6,4,0],[7,2,3],[8,3,6],[5,1,9]]
# → [[6,7,8,5],[4,2,3,1],[0,3,6,9]]
# (And implicitly output the now sorted matrix)





$begingroup$
I got diø}Σ¹Ä<è]¹diø which is a subset of yours, so I'm not posting a separate answer.
$endgroup$
– Emigna
Sep 12 '18 at 19:36


diø}Σ¹Ä<è]¹diø





$begingroup$
@Emigna Dang, you make it look so easy.. Now that I see it I can't believe I hadn't thought about that myself, but it's ingenious at the same time.. Thanks! A whopping 10 bytes saved thanks to you.
$endgroup$
– Kevin Cruijssen
Sep 12 '18 at 20:32



JavaScript (ES6), 90 bytes


t=m=>m[0].map((_,x)=>m.map(r=>r[x]))
f=(m,k)=>k<0?m.sort((a,b)=>a[~k]-b[~k]):t(f(t(m),-k))



Try it online!



JS has no native transposition method, so we need to define one:


t = m => // given a matrix m
m[0].map((_, x) => // for each column at position x in m:
m.map(r => // for each row r in m:
r[x] // map this cell to r[x]
) // end of map() over rows
) // end of map() over columns



Main function:


f = (m, k) => // given a matrix m and an integer k
k < 0 ? // if k is negative:
m.sort((a, b) => // given a pair (a, b) of matrix rows, sort them:
a[~k] - b[~k] // by comparing a[-k - 1] with b[-k - 1]
) // end of sort
: // else:
t(f(t(m), -k)) // transpose m, call f() with -k and transpose the result



Example with $k=2$:



$$M=pmatrix5&8&7&6\1&3&2&4\9&6&3&0rightarrow
t(M)=pmatrix5&1&9\8&3&6\7&2&3\6&4&0rightarrow
f(t(M),-2)=pmatrix5&mathbfcolorred1&9\7&mathbfcolorred2&3\8&mathbfcolorred3&6\6&mathbfcolorred4&0\f(M,2)=t(f(t(M),-2))=pmatrix5&7&8&6\mathbfcolorred1&mathbfcolorred2&mathbfcolorred3&mathbfcolorred4\9&3&6&0$$




MATL, 17 bytes


y0>XH?!]w|2$XSH?!



Try it online!



Or verify all test cases


y % Implicit inputs: number n, matrix M. Duplicate from below: pushes n, M, n
0> % Greater than 0?
XH % Copy into clipboard H
? % If true
! % Transpose matrix. This way, when we sort the rows it will correspond
% to sorting the columns of the original M
] % End
w % Swap: moves n to top
| % Absolute value
2$XS % Two-input sortrows function: sorts rows by specified column
H % Push contents from clipboard H
? % If true
! % Transpose again, to convert rows back to columns
% Implicit end
% Implicit display




APL (Dyalog Classic), 23 bytes


⍺<0:⍉(-⍺)∇⍉⍵⋄⍵[;⍋⍺⌷⍵]



Try it online!




Python 2, 71 70 bytes


f=lambda m,n:n<0and sorted(m,key=lambda l:l[~n])or zip(*f(zip(*m),-n))



Try it online!



If n is negative, the rows are sorted based on column n.


n


n



Otherwise the matrix is transposed, sorted the same way, and transposed back again.




Jelly, 12 bytes


ZṠ}¡
çị@ÞA}ç



Try it online!




C# (.NET Core), 186 bytes


(x,y)=>Func<int,int>shift=a=> a[0].Select((r,i)=>a.Select(c=>c[i]).ToArray()).ToArray();return y>0?shift(shift(x).OrderBy(e=>e[y-1]).ToArray()):x.OrderBy(e=>e[-y-1]).ToArray();



Try it online!



Ungolfed:


private static int Blocksort0a(int array, int sortingInstruction)

Func<int, int> shift = a => a[0].Select((r, i) => a.Select(c => c[i]).ToArray()).ToArray();

sortingInstruction++;

array = sortingInstruction < 0 ?
shift(shift(array).OrderBy(e => e[-sortingInstruction]).ToArray())
:
array.OrderBy(e => e[sortingInstruction]).ToArray();

return null;



The shift function we'll use twice, so a function variable will save space. The function iterates through the horizontal dimension of the array on index, and adds every item on that index in of each horizontal array to a new output array (horizontally) - much the same as in Arnoud's JS solution.



Now the ordering is simple, order horizontal array by number-at-index (argument -1), optionally shifting the array before and after sorting.



Seen how the question talks about arrays specifically, we convert to array a few times (very, very wasteful). Feeling a bit silly to use such a verbose language in code golf hehe.




C# (.NET Core), 142/139 138/135 bytes (and yet another -1 by Kevin)


(a,s)=>s<0?a.OrderBy(e=>e[~s]).ToArray():a.Select(f=>a[s-1].Select((v,j)=>newv,j).OrderBy(e=>e.v).Select(e=>f[e.j]).ToArray()).ToArray()



Try it online!



Ungolfed:


private static int Blocksort0b(int array, int sortingInstruction)

if (sortingInstruction < 0) return array.OrderBy(e => e[-sortingInstruction - 1]).ToArray();
var rowIndices = array[sortingInstruction - 1].Select((value, index) => (value, index)).OrderBy(e => e.value);
var newRow = new int[array[0].Length];
for (var i = 0; i < array.Length; i++)

int horizontalIndexer = 0;
foreach (var e in rowIndices)

newRow[horizontalIndexer++] = array[i][e.index];

array[i] = newRow.ToArray();

return array;



New all-inline approach; negative answer still orders arrays by element-at-index. Otherwise, a collection of value-index-pair is created of the array-at-index and sorted by value. This effectively creates a collection of indices in order of having-to-be-added. Then for each array, the elements in the predetermined positions are selected. Quite some trimming of code and ugly, ugly, ugly &ast;&ast;silently sobs&ast;&ast; reuse of input parameters is involved, and there you go ... 142 bytes.



Again, the arrays argument is strictly enforced, adding quite some overhead for .ToArray() calls.



135 bytes claim, eh?! C# 7.2 inferred value-tuples would trim an additional three bytes, but tio.run doesn't allow. Therefor, this is the answer i decided to post for easy verification.





$begingroup$
Nice answer. There are a few small things to golf. (a,s)=> can be a currying a=>s=>. (s<0)? doesn't need the parenthesis, and -s-1 can be ~s. Try it online: 137 bytes
$endgroup$
– Kevin Cruijssen
Sep 12 '18 at 20:55


(a,s)=>


a=>s=>


(s<0)?


-s-1


~s





$begingroup$
Sweet! I never would've through of letting the function return yet another function to save a character, i am pleasantly surprised. Thanks! Also a strong case of blatantly overlooking the not operator and parenthesis. I updated the not and parentheses, but will leave you all the honour for the function-returning-function.
$endgroup$
– Barodus
Sep 12 '18 at 21:48





Java (OpenJDK 8), 326 bytes


(a,b)->int l=a.length,w=a[0].length,k,m,t,i;if(b>0)for(i=0;i<w;i++)for(k=1;k<(w-i);k++)if(a[b-1][k-1]>a[b-1][k])for(m=0;m<l;m++)t=a[m][k];a[m][k]=a[m][k-1];a[m][k-1]=t;elseb*=-1;for(i=0;i<l;i++)for(k=1;k<(l-i);k++)if(a[k-1][b-1]>a[k][b-1])for(m=0;m<w;m++)t=a[k][m];a[k][m]=a[k-1][m];a[k-1][m]=t;return a;



Try it online!



Well guys, this question was very frustrating for me, and I posted my answer KNOWING I was forgetting something, luckily we have legends like Kevin Cruijssen out here to help us out :)




Java (OpenJDK 8), 281 bytes


a->b->int l=a.length,w=a[0].length,k,m,t,i;if(b>0)for(i=0;i<w;i++)for(k=0;++k<w-i;)for(m=0;a[b-1][k-1]>a[b-1][k]&m<l;a[m][k]=a[m][k-1],a[m++][k-1]=t)t=a[m][k];else for(b*=-1,i=0;i<l;i++)for(k=0;++k<l-i;)for(m=0;a[k-1][b-1]>a[k][b-1]&m<w;a[k][m]=a[k-1][m],a[k-1][m++]=t)t=a[k][m];



Try it online!





$begingroup$
I haven't looked at the actual algorithm yet, but you can save 35 bytes by removing all the brackets and putting everything inside the loops (including the inner if-statement). Try it online: 291 byte EDIT: Here with space indentations so you can more clearly see the changes I did.
$endgroup$
– Kevin Cruijssen
Sep 12 '18 at 20:44






$begingroup$
@KevinCruijssen I knew I was missing something
$endgroup$
– X1M4L
Sep 12 '18 at 20:49





$begingroup$
In addition, you can make it a currying input a->b-> instead of (a,b)-> and remove the return-statement, since you are modifying the input-array. 281 bytes Still a nice answer, though. +1 from me. I did the challenge in 05AB1E, but wouldn't even have tried it in Java this time. ;)
$endgroup$
– Kevin Cruijssen
Sep 12 '18 at 20:50



a->b->


(a,b)->


return




Clean, 95 bytes


import StdEnv,Data.List,Data.Func
$n#f=if(n>0)transpose id
=f o sortBy(on(<)u=u!!(abs n-1))o f



Try it online!




Kotlin, 192 bytes


m:Array<Array<Int>>,s:Int->if(s<0)m.sortByit[-s-1]elseval a=Array(m[0].size)c->Array(m.size)m[it][c]
a.sortByit[s-1]
(0..m.size-1).mapr->(0..m[0].size-1).mapm[r][it]=a[it][r]



Try it online!




Ruby, 69 bytes


->a,nf=->x[0,x.transpose,x][n<=>0];f[f[a].sort_byx[n.abs-1]]



Try it online!



VBA (Excel), 205 bytes



Yay! 2nd longest byte count! I didn't completely lose :D



Golfed:


Sub d(a)
With ActiveSheet.Sort
.SortFields.Clear
.SortFields.Add Key:=IIf(a<0,ActiveSheet.Columns(Abs(a)),ActiveSheet.Rows(Abs(a)))
.SetRange ActiveSheet.UsedRange
.Orientation=IIf(a<0,1,2)
.Apply
End With
End Sub



This sorts all the data on the open (active) worksheet using UsedRange... which can be buggy, but should only contain cells that have been edited.



UnGolfed:


Sub d(a)
'Clear any Sort preferences that already exists
ActiveSheet.Sort.SortFields.Clear
'Use the column if A is negative, the row if A is positive
ActiveSheet.Sort.SortFields.Add Key:=IIf(a < 0, ActiveSheet.Columns(Abs(a)), ActiveSheet.Rows(Abs(a)))
'Set the area to sort
ActiveSheet.Sort.SetRange ActiveSheet.UsedRange
'Orient sideways if sorting by row, vertical if by column
ActiveSheet.Sort.Orientation = IIf(a < 0, xlTopToBottom, xlLeftToRight)
'Actually sort it now
ActiveSheet.Sort.Apply
End Sub




Perl 6, 43 bytes


($!=$_>0??&[Z]!!*)o*.sort(*[.abs-1])o$!



Try it online!



Curried function.


# Block returning function composed of
o$! # 1. Apply $! (transpose or not)
o*.sort(*[.abs-1]) # 2. Sort rows by column abs(i)-1
$_>0??&[Z] # 3. If i > 0 transpose matrix
!!* # Else identity function
($!= ) # Store in $!




Physica, 45 bytes



Very similar to Arnauld's JS answer.


F=>n;m:n<0&&Sort[->u:u~n;m]||Zip@F#Zip@m#-n



Try it online!



A more elaborate and visual explanation can be found in the linked answer.


F=>n;m: // Create a function F that takes two arguments, n and m.
n<0&& // If n < 0 (i.e. is negative)
Sort[->u~n;m] // Sort the rows u of m by the result of the function u[~n].
// In short, sort by indexing from the end with n.
|| F#Zip@m#-n // Else, apply F to Zip[m] and -n. Uses a new feature, binding.
Zip@ // And transpose the result.




Red, 190 bytes


func[b n][t: func[a][c: length? a/1 a: to-block form a
d: copyloop c[append/only d extract a c take a]d]d: does[if n > 0[b: t b]]d
m: absolute n sort/compare b func[x y][x/(m) < y/(m)]d b]



Try it online!


f: func [ b n ] [
t: func [ a ] [ ; helper transpose function
c: length? a/1 ; c is the length of the rows
a: to-block form a ; flatten the list
d: copy ; an empty block (list)
loop c [ ; do as many times as the number of columns
append/only d extract a c ; extract each c-th element (an entire column)
; and append it as a sublist to d
take a ; drop the first element
]
d ; return the transposed block (list of lists)
]
d: does [ if n > 0 [ b: t b ] ] ; a helper function (parameterless) to transpose
; the array if positive n
d ; call the function
m: absolute n ; absolute n
sort/compare b func[ x y ] [ x/(m) < y/(m) ]; sort the array according to the chosen column
d ; transpose if positive n
b ; return the array
]



My actual solution is 175 bytes long, but it doesn't work in TIO. Here it is, working normalyl in the Red console:


func[b n][d: does[if n > 0[c: length? b/1 a: to-block form b
t: copyloop c[append/only t extract a c take a]b: t]]d
m: absolute n sort/compare b func[x y][x/(m) < y/(m)]d b]



If this is an answer to a challenge…



…Be sure to follow the challenge specification. However, please refrain from exploiting obvious loopholes. Answers abusing any of the standard loopholes are considered invalid. If you think a specification is unclear or underspecified, comment on the question instead.



…Try to optimize your score. For instance, answers to code-golf challenges should attempt to be as short as possible. You can always include a readable version of the code in addition to the competitive one.
Explanations of your answer make it more interesting to read and are very much encouraged.



…Include a short header which indicates the language(s) of your code and its score, as defined by the challenge.



More generally…



…Please make sure to answer the question and provide sufficient detail.



…Avoid asking for help, clarification or responding to other answers (use comments instead).



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)