Can you sort a list by functions rather than properties?

I want to sort a deck of cards by suit, then by rank.

A card is a kind of thing. A card has a number called suit. A card has a number called rank.
AS is a card with suit 1 and rank 1. 2S is a card with suit 1 and rank 2. AC is a card with suit 2 and rank 1. 2C is a card with suit 2 and rank 2. [etc]

To decide what number is the position of (c - a card): decide on 13 * the suit of c + the rank of c.

Every turn:
    let deck be the list of cards;
    sort deck in position order;
    ...

This doesn’t work (obviously, that’s why I’m asking). I could I guess sort by rank, then by suit, but that relies on the sort being stable, which I don’t know if it is, and isn’t terribly clear or extensible anyways. Is there a way of doing what I want here?

I don’t think there’s any way to do that with the built-in sort phrase, although you could probably do it if you implemented a sorting algorithm manually.

You could make position a property as well:

A card has a number called position.

When play begins:
	repeat with c running through all cards:
		now the position of c is 13 * the suit of c + the rank of c.

Now the sort deck in position order will work.

If you have events that alter the suit/rank of a specific card then you’ll have to update its position as well; they aren’t automatically linked.

Another thing that might be worth considering (depending on your goal) is the approach shown in the Tilt 1 example, where cards are initially anonymous; the reconstitute the deck phrase effectively creates a sorted deck by reassigning the cards in a specific order (although it doesn’t maintain that specific order).

Ungh, that’s not super great, but I suppose the “make a quick extra property and populate it at the start” approach works. Thanks. :slight_smile:

If you don’t mind a text-based sort, another option would be to abuse the fact that text properties are actually routines:

A card has some text called position.
The position of a card is always "[suit of item described]-[rank of item described]".

This still gives the cards an extra property but the value of this will be automatically calculated. You can use some other expressions (including To say expressions) to vary the ordering – but note that as written, because this is a text sort without zero prefix, this is going to sort rank 10 right after rank 1, which is probably not what you want. It’s also almost certainly a bit slower than the other method.

1 Like

This doesn’t work, I’m afraid. The position values aren’t reduced to substituted form, so every card has the same position value, and the sort has no effect.

1 Like

It is.

The method of sorting is “stable”, that is, if two rows have the same value then they will stay the same way round in the sorted table, rather than being swapped over.

Ah, whoops. I tested that it compiled and it had the right showme output and the right sorted order – but overlooked that the cards were already created in sorted order to start with.

I’m surprised it’s not comparing the substituted values, though; that’s how most other things seem to treat text properties. It does work as expected if I explicitly assign simple text to each card.

To be fair, that particular reference only refers to table sorts; not list sorts. Hopefully those are stable too.

So to round that out, this does work to sort them in order, at least in a small test:

	sort deck in rank order;
	sort deck in suit order;

For the curious: current I7 does use the same algorithm for both table and list sorting; specifically, a tiled merge sort.