ahndreklicyri

Hehe funny gun goes BRRRT

  • He/Him

23 | Male | Programmer | 18+ Only!


zanzlanz
@zanzlanz

(Before I explain - I had 5 megabytes to compress a gif of literal noise haha, so please forgive how absolutely crunchy it is. Below is a much higher quality video version!)

Ok, so here's the problem:
How do you sort a 2D array in 2 dimensions at once?

For example, in the above gif, I'm sorting both hue and lightness to make the final rainbow. Sounds simple to sort, until you consider two issues:

  1. You have to stick to the grid - you can't double up pixels.
  2. In normal situations, you'll have data that skews to certain hues.

The real-world scenario I encountered this in was my desire to sort player-made characters in a grid, by color. I can plot them by color, and I can place them in a grid arbitrarily, but how can I do both?

A large image of 6951 pixel art characters, sorted by color. The characters are overlapping and clumped.
A perfect grid of 6954 pixel art characters, with no obvious sorting.
(Zoom in - that's 6,954 player-made skins for my game Mine Blocks! ❤)

The solution I ended up with is what I call JostleSort™:

  • I swap pixels with their nearby neighbors if doing so would make them more sorted.
  • The swapping occurs further away if the pixel thinks it's less sorted.
  • It "jostles" it around a bit, like sifting sand, in order to avoid local minima and stalemates.

My solution is honestly very slow, and it feels like a brute force solution. But I can't think of a better way to do it... can you think of any ideas?

Here's a much higher quality video than the first one (if you're on desktop at least; on mobile, Streamable compresses it a lot more), however I must warn you: tragically, it ends too early! Unfortunately I had to stop it so I could sleep.

For further research: the general problem in this post is one of dimensionality reduction. My concept feels similar to gradient descent, but... nothing seems to consider sorting things in a packed 2D array?


You must log in to comment.

in reply to @zanzlanz's post:

This probably isn't optimal, but here's a sketch of something that might be fast / flexible enough if you have some extra memory space. If you sort all of the points by luminance (let's say hue for columns and luminance for rows) you can then 1) decide on the dimensions of your grid (say n columns x m rows), take the lowest n luminance values and sort them by hue, and write that into column 1, and keep going. That'll be pretty fast since the inner sorts are quicker than sorting the whole list twice. Will it work for your application?

I suspect if you know the dimensions of your grid in advance you can get something much better, basically "plot everything into rectangular buckets and then solve a problem with the buckets".

Oh those ideas get me thinking, thanks! I wonder what an approach that uses quad trees would look like; I can't seem to wrap my mind around relating this problem to traditional sorting algorithms, because elements will get stuck depending on which axis you're sorting on. For example if you sort horizontally and vertically a bunch of times, you get little + signs

If you do multiple sorting passes over the same data you should look into using a stable sorting algorithm. Unstable sorting can mess up the previous sorting passes.

I don't think the approach of @joeatwork would be affected by that, because it divides the list up into sublists, but it is something to look out for.

Whoa! That looks great, thanks for taking a stab at it!

I hadn't thought of the cocktail sort - that's very clever, since it should handle clumped data much more elegantly than other asymmetric sorts.

I'd love to check it out. Do you have a gist or demo of it?

Incredible!! I just gave it a shot in my language of choice.

I was so used to mine taking hours to converge, that I was completely dumbfounded seeing your implementation work at 14 FPS. So much more practical!

One thing that this technique doesn't quite solve is that the results are still anisotropic; you can get different patterns if you sort values before hues. I have a feeling that's unavoidable with traditional sorting algorithms, so perhaps this is the best option for the speed and predictability.

Example of anisotropic behavior (through adding a bunch of one color):

Hue first: https://staging.cohostcdn.org/attachment/8717b274-007c-49ec-954e-306f045c6df7/hue%20first.gif

Value first: https://staging.cohostcdn.org/attachment/f41e7919-4787-4317-b944-d166c9a32ff0/value%20first.gif

Thanks again so much for contributing your ideas!

Your approach of making the swaps further away for less-sorted neighbors vaguely reminds me of Comb Sort: https://en.wikipedia.org/wiki/Comb_sort

What if you make it more like comb sort and instead of swapping a further distance only if it thinks it's far off, you instead have a separate phases where everything uses a large-distance swap, followed by phases that decrease the swap distance? I'm curious if it would make things faster.

I've never heard of Comb sort before - it's almost surprising that actually works even in 1D!

I'm trying to translate that idea to 2D. So, I'd compare each pixel to every pixel that's an exact radius away, and swap if it's bigger. And then do a bunch of passes until the radius is 1 pixel away. Perhaps Euclidean distance instead of a radius would be easier to implement at first...

Cool idea! Thank you for your thoughts!