views:

240

answers:

8

Here's the scenario.

I have one hundred car objects. Each car has a property for speed, and a property for price. I want to arrange images of the cars in a grid so that the fastest and most expensive car is at the top right, and the slowest and cheapest car is at the bottom left, and all other cars are in an appropriate spot in the grid.

What kind of sorting algorithm do I need to use for this, and do you have any tips?

EDIT: the results don't need to be exact - in reality I'm dealing with a much bigger grid, so it would be sufficient if the cars were clustered roughly in the right place.

+1  A: 

Basically you have to take one of speed or price as primary and then get the cars with the same value of this primary and sort those values in ascending/descending order and primaries are also taken in the ascending/descending order as needed.

Example:

c1(20,1000) c2(30,5000) c3(20, 500) c4(10, 3000) c5(35, 1000)

Lets Assume Car(speed, price) as the measure in the above list and the primary is speed.

1 Get the car with minimum speed

2 Then get all the cars with the same speed value

3 Arrange these values in ascending order of car price

4 Get the next car with the next minimum speed value and repeat the above process

c4(10, 3000)
c3(20, 500)
c1(20, 1000)
c2(30, 5000)
c5(35, 1000)

If you post what language you are using them it would we helpful as some language constructs make this easier to implement. For example LINQ makes your life very easy in this situation.

cars.OrderBy(x => x.Speed).ThenBy(p => p.Price);

Edit:

Now you got the list, as per placing this cars items into the grid unless you know that there will be this many number of predetermined cars with these values, you can't do anything expect for going with some fixed grid size as you are doing now.

One option would be to go with a nonuniform grid, If you prefer, with each row having car items of a specific speed, but this is only applicable when you know that there will be considerable number of cars which has same speed value.

So each row will have cars of same speed shown in the grid.

Thanks

Mahesh Velaga
Thanks for adding the LINQ! That's very helpful. Any idea what rules would be appropriate for arranging the results into a grid?
CentralScrutinizer
@CentralScrutinizer: see edit for some hints from my side. Thanks
Mahesh Velaga
+5  A: 

Treat this as two problems:

1: Produce a sorted list 2: Place members of the sorted list into the grid

The sorting is just a matter of you defining your rules more precisely. "Fastest and most expensive first" doesn't work. Which comes first my £100,000 Rolls Royce, top speed 120, or my souped-up Mini, cost £50,000, top speed 180?

Having got your list how will you fill it? First and last is easy, but where does number two go? Along the top or down? Then where next, along rows, along the columns, zig-zag? You've got to decide. After that coding should be easy.

djna
For ordering, one would assume a standard left-to-right, top-to-bottom approach.
DisgruntledGoat
why would you assume that? Diagnonal zig-zag might give nice adjencny of similar vehicles. My major point is that once you make your requirements clear the code often just falls out, by clarifying what you aid thinking about how (as well as avoiding writing the wrong thing.)
djna
+1  A: 

Is the 10x10 constraint necessary? If it is, you must have ten speeds and ten prices, or else the diagram won't make very much sense. For instance, what happens if the fastest car isn't the most expensive?

I would rather recommend you make the grid size equal to

  (number of distinct speeds) x (number of distinct prices), 

then it would be a (rather) simple case of ordering by two axes.

Zano
A: 

If the data originates in a database, then you should order them as you fetch them from the database. This should only mean adding ORDER BY speed, price near the end of your query, but before the LIMIT part (where 'speed' and 'price' are the names of the appropriate fields).

As others have said, "fastest and most expensive" is a difficult thing to do, you ought to just pick one to sort by first. However, it would be possible to make an approximation using this algorithm:

  1. Find the highest price and fastest speed.
  2. Normalize all prices and speeds to e.g. a fraction out of 1. You do this by dividing the price by the highest price you found in step 1.
  3. Multiply the normalized price and speed together to create one "price & speed" number.
  4. Sort by this number.

This ensures that is car A is faster and more expensive than car B, it gets put ahead on the list. Cars where one value is higher but the other is lower get roughly sorted. I'd recommend storing these values in the database and sorting as you select.

Putting them in a 10x10 grid is easy. Start outputting items, and when you get to a multiple of 10, start a new row.

DisgruntledGoat
A: 

Another option is to apply a score 0 .. 200% to each car, and sort by that score.

Example:

score_i = speed_percent(min_speed, max_speed, speed_i) + price_percent(min_price, max_price, price_i)
Nick D
+7  A: 

Just an idea inspired by Mr Cantor:

  • calculate max(speed) and max(price)
  • normalize all speed and price data into range 0..1
  • for each car, calculate the "distance" to the possible maximum

based on a²+b²=c², distance could be something like

sqrt( (speed(car[i])/maxspeed)^2 + (price(car[i])/maxprice)^2 )

apply weighting as (visually) necessary

  • sort cars by distance
  • place "best" car in "best" square (upper right in your case)
  • walk the grid in zigzag and fill with next car in sorted list

Result (mirrored, top left is best):

1 - 2   6 - 7
  /   /   /
3   5   8
| /
4
devio
+1. Even better, he could have not a grid but a square area in which cars are placed as dots in their exact position according to the calculated normalized coordinates. A tooltip would show the actual image and details of the currently viewed car.
Daniel Daranas
Awesome, thanks devio!
CentralScrutinizer
Performance note (can't help myself) - the sqrt is not necessary.
Daniel Paull
+2  A: 

I guess what you want is to have cars that have "similar" characteristics to be clustered nearby, and additionally that the cost in general increases rightwards, and speed in general increases upwards.

I would try to following approach. Suppose you have N cars and you want to put them in an X * Y grid. Assume N == X * Y.

  1. Put all the N cars in the grid at random locations.
  2. Define a metric that calculates the total misordering in the grid; for example, count the number of car pairs C1=(x,y) and C2=(x',y') such that C1.speed > C2.speed but y < y' plus car pairs C1=(x,y) and C2=(x',y') such that C1.price > C2.price but x < x'.
  3. Run the following algorithm:
    1. Calculate current misordering metric M
    2. Enumerate through all pairs of cars in the grid and calculate the misordering metric M' you obtain if you swapt the cars
    3. Swap the pair of cars that reduces the metric most, if any such pair was found
    4. If you swapped two cars, repeat from step 1
    5. Finish

This is a standard "local search" approach to an optimization problem. What you have here is basically a simple combinatorial optimization problem. Another approaches to try might be using a self-organizing map (SOM) with preseeded gradient of speed and cost in the matrix.

antti.huima
A: 

Hmmm... kind of bubble sort could be simple algorithm here.

  1. Make a random 10x10 array.
  2. Find two neighbours (horizontal or vertical) that are in "wrong order", and exchange them.
  3. Repeat (2) until no such neighbours can be found.

Two neighbour elements are in "wrong order" when: a) they're horizontal neighbours and left one is slower than right one, b) they're vertical neighbours and top one is cheaper than bottom one.

But I'm not actually sure if this algorithm stops for every data. I'm almost sure it is very slow :-). It should be easy to implement and after some finite number of iterations the partial result might be good enough for your purposes though. You can also start by generating the array using one of other methods mentioned here. Also it will maintain your condition on array shape.

Edit: It is too late here to prove anything, but I made some experiments in python. It looks like a random array of 100x100 can be sorted this way in few seconds and I always managed to get full 2d ordering (that is: at the end I got wrongly-ordered neighbours). Assuming that OP can precalculate this array, he can put any reasonable number of cars into the array and get sensible results. Experimental code: http://pastebin.com/f2bae9a79 (you need matplotlib, and I recommend ipython too). iterchange is the sorting method there.

liori
You can guarantee it will terminate by initially sorting the cars by speed, then placing the fastest cars top to bottom then left to right. Then if faster cars go to the left, there's on way swapping up-down based on price will break the speed ordering. So it becomes equivalent to sorting all the columns by price. You end up with speed 'classes' with best price at the top.
Strilanc
Ha, I made a visualization: http://files.exroot.org/dump/2dbubble.avi (kind of blurry, but it was done in 15 minutes). Each pixel's parameters are encoded by red and green intensities; blue intensity set to 1.0 for all pixels.
liori
CentralScrutinizer: thanks for 3 hours of fun :-)
liori