yvi: (Dreamwidth - Developer: winter)
yvi ([personal profile] yvi) wrote in [site community profile] dw_dev_training2009-11-24 12:30 pm
Entry tags:

Need some help: tag sorting

Since [staff profile] denise asked so nicely, I might put up some questions during the next few days.

I apologize if this description is messy - I can be very bad at explaining these things.

One of the bugs I am currently stuck on is http://bugs.dwscoalition.org/show_bug.cgi?id=2012 use a tag list not a tag cloud on the subscription filter interface The goal is to change th tag cloud here: http://www.dreamwidth.org/manage/subscriptions/filters to an alphabetically sorted tag list with usage numbers. Despite my complete inability with javaScript, I managed the 'tag list with usage numbers' part fine. I am, however, stuck on the alphabetically sorted part.

It looks like sorting the tags before they reach that point might be the way to go and htdocs/tools/endpoints/general.bml might be the key to that.

} elsif ( $mode eq 'list_tags' ) {
        $ret{tags} = LJ::Tags::get_usertags( $u, { remote => $remote } );


get_usertags returns a "Hashref; key being tag id, value being a large hashref". It looks like hashes in perl can be sorted - is there a way to sort this hash by name? I imagine this structure looks something like:

hash{id1} = { 'name' => name1,
'usage' => usage1,
...}
hash{id2} = { 'name' => name2,
'usage' => usage2,
...}

and now I need to sort the ids by name.

There is some sorting going on in cgi-bin/LJ/S2/TagPage.pm:

    my $tags = LJ::Tags::get_usertags($u, { remote => $remote });
    foreach my $kwid (keys %{$tags}) {
        # only show tags for display
        next unless $tags->{$kwid}->{display};
        push @taglist, LJ::S2::TagDetail($u, $kwid => $tags->{$kwid});
    }
    @taglist = sort { $a->{name} cmp $b->{name} } @taglist;


But that returns a sorted array.

Any ideas?

EDIT: Okay, looks like I either need to sort the ids by name and then return both the hashref and the array and handle that in the JavaScrript portion or sort in htdocs/js/subfilters.js itself. The relevant code is in function cfUpdateTags( data ), the for ( id in data.tags ) { loop would need to be run through in order of data.tags[id].name.
pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)

[personal profile] pne 2009-11-24 12:37 pm (UTC)(link)
It looks like hashes in perl can be sorted

Not as such. What people usually do is get the list of keys of that hash, and sort the list; then use the sorted list of keys to access the corresponding hash entry. (So something like for $key (sort keys %hash) { $value = $hash{$key}; do_something_with($value) }.) (BTW, for is an alias for foreach, so you could also go with foreach my $key (sort keys %hash) { ... }.) (And if you have a hashref, then something like for $key (sort keys %{$hashref}) { $value = $hashref->{$key}; do_something_with($value) }.)

I imagine this structure looks something like:

Yes, though probably with hash->{id1} rather than hash{id1} since you have a hashref rather than a hash.

But that returns a sorted array.

Yes, an array of objects (whatever LJ::S2::TagDetail returns), with those objects sorted by their names. Are those unsuitable for your purpose?
pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)

[personal profile] pne 2009-11-24 01:46 pm (UTC)(link)
I tried to reply to this but the comment was apparently posted as a top-level comment.
pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)

[personal profile] pne 2009-11-24 01:46 pm (UTC)(link)
The thing is, I don't need to sort by keys, I need to sort by ->{key}->{name} or ->{key}{name}, however that works.

Then I think you'll need something like foreach my $key (sort { $tags->{$a}->{name} cmp $tags->{$b}->{name} } keys %{$tags}) { ... }. (Let me know if you'd like that bit explained to you.)

(Oh, and ->{key}->{name} and ->{key}{name} mean the same thing; you can omit the -> between adjacent brackets with hash keys or array subscripts.)

The impression I got from a bit of googling is that hashes/hashrefs in perl retain the order they were built in, as opposed to dictionaries in python, which do not have an order.

No, that's not so -- perhaps you're confusing them with arrays in PHP? They're an unholy combination of hashes/dictionaries and arrays: they allow numbers as keys (like arrays) or strings (like hashes), and retain their order.

Perl hashes iterate in random order, pretty mich like dictionaries in Python. And adding a value to a hash can cause the order of the remaining keys to change, as can switching the Perl version. Basically, you shouldn't rely on the order of keys in a hash.

Also, $value in this case would be hash itself, right?

Well, a hashref, so kind of.

So I would do something like [...] and get the same structure as before, only with sorted keys?

No. If you need order preserved, you'll need either a list or an array. (Note that a list is an ephemeral data structure; there aren't any variables of list type. sort returns a list, for example, which you can then assign to an array - or process further, e.g. by iterating over it with foreach.)
pne: A picture of a plush toy, halfway between a duck and a platypus, with a green body and a yellow bill and feet. (Default)

[personal profile] pne 2009-11-24 02:01 pm (UTC)(link)
the end result of sorting a hash was not in fact a hash, but a sorted arrays of the keys.

A sorted list, strictly speaking.

But yes. Because you can't sort hashes - you sort the list of keys. (Either by the key themselves, or by something based on the key, depending on what you want to accomplish.)