Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by hippo (Bishop) on Jul 21, 2022 at 16:47 UTC
|
#!/usr/bin/env perl
use strict;
use warnings;
use Digest::SHA 'sha512256_hex';
my @weekdays = qw/Monday Saturday Thursday/;
print join ",", map { $_->[0] }
sort { $a->[1] cmp $b->[1] }
map { [$_, substr (sha512256_hex (substr (lc ($_), 1, 7)), 26, 1)] } @
+weekdays;
| [reply] [d/l] |
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by choroba (Cardinal) on Jul 22, 2022 at 09:50 UTC
|
This still uses the %order, but populates it via a core module:
use Time::Piece;
my %order = map {
split ' ', 'Time::Piece'->strptime("$_", "%d")->strftime('%A %u')
} 1 .. 7;
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] [select] |
|
bravo choroba!
I was trying something similar but I easily get annoyed by strptime et similia...
Infact even with your code I hit Error parsing time at C:/perl5.26.64bit/perl/lib/Time/Piece.pm line 581.
I'd modify your code to be even more stable, in the case they accept my proposal for 8 days week, adding Lokiday as jolly day free for all :D
my %order = map {
split ' ', 'Time::Piece'->strptime("$_", "%d")->strftime('%A %u')
} Time::Piece::day_list();
bliako: your solution is already elegant, readable and perlish: dont overcomplicate :)
L*
There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
| [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
|
> perl -de0
DB<38> use Time::Piece
DB<39> x Time::Piece::day_list
0 'Sun'
1 'Mon'
2 'Tue'
3 'Wed'
4 'Thu'
5 'Fri'
6 'Sat'
DB<40> x @{Time::Piece::_get_localization->{weekday}}
0 'Sunday'
1 'Monday'
2 'Tuesday'
3 'Wednesday'
4 'Thursday'
5 'Friday'
6 'Saturday'
And if you don't like the traditional order
DB<41> @W = @{Time::Piece::_get_localization->{weekday}}
DB<42> push @W, shift @W
DB<43> x @W
0 'Monday'
1 'Tuesday'
2 'Wednesday'
3 'Thursday'
4 'Friday'
5 'Saturday'
6 'Sunday'
DB<44>
| [reply] [d/l] [select] |
|
Hmm... Not present in 5.26.1, works but not documented in 5.37.1. I'm not sure I'd use it.
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
|
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by tybalt89 (Monsignor) on Jul 21, 2022 at 15:49 UTC
|
#!/usr/bin/perl
use strict; # https://perlmonks.org/?node_id=11145633
use warnings;
use List::AllUtils qw( nsort_by );
my @weekdays = qw/Monday Saturday Thursday/;
print "$_\n" for
nsort_by { 'motuwethfrsasu' =~ substr lc, 0, 2; $-[0] } @weekdays;
Outputs:
Monday
Thursday
Saturday
| [reply] [d/l] [select] |
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by haukex (Archbishop) on Jul 22, 2022 at 14:10 UTC
|
use List::Util qw/shuffle/;
my @weekdays = shuffle qw/ Monday Tuesday Wednesday
Thursday Friday Saturday Sunday /;
say join ", ", map { $$_[0] } sort { $$a[1] cmp $$b[1] }
map { [$_, lc(substr $_,0,2)=~tr/softwarehum/50411307860/r] }
@weekdays;
Update: Anagram'd | [reply] [d/l] |
|
#!/usr/bin/perl
use strict; # https://perlmonks.org/?node_id=11145633
use warnings;
use List::AllUtils qw( shuffle sort_by );
my @weekdays = shuffle
qw/Monday tuesday wednesday friday sunday Saturday Thursday/;
print "@{[ sort_by { lc =~ tr/muwhft/a-e/dr } @weekdays ]}\n";
| [reply] [d/l] |
|
++tybalt89!! That was a very clever use of "tr" and its options. I added a small tweak using unshift and pop to put Sunday first.
#!/usr/bin/perl
use strict;
use warnings;
use List::AllUtils qw( shuffle sort_by );
my @weekdays = shuffle qw/Monday Tuesday Wednesday Friday Sunday Satur
+day Thursday/;
@weekdays = @{[ sort_by { lc =~ tr/muwhft/a-e/dr } @weekdays ]};
unshift(@weekdays,pop(@weekdays));
print "@weekdays\n";
"It's not how hard you work, it's how much you get done."
| [reply] [d/l] |
|
|
|
Re: Challenge: sort weekdays in week-order (Sort::Key)
by LanX (Saint) on Jul 21, 2022 at 15:25 UTC
|
Using Salva's Sort::Key is efficient and elegant, but I can't get rid of the order info
use v5.12;
use warnings;
use Sort::Key qw/ikeysort/;
use Data::Dump qw/pp dd/;
my $n;
my %order = map {$_ => ++$n}
qw/monday tuesday wednesday thursday friday saturday sunday/;
pp ikeysort { $order{lc($_)} } qw/Monday Saturday Thursday/;
==>
("Monday", "Thursday", "Saturday")
edit
oops wait, there is a bug...
update
Fixed bug in %order creation
| [reply] [d/l] [select] |
Re: Challenge: sort weekdays in week-order (grep)
by LanX (Saint) on Jul 21, 2022 at 15:08 UTC
|
use v5.12;
use warnings;
use Data::Dump qw/pp dd/;
my $input = join "|", qw/Monday Saturday Thursday/;
my @order = qw/monday tuesday wednesday thursday friday saturday sunda
+y/;
pp grep { /^($input)$/i } @order;
==>
("monday", "thursday", "saturday")
| [reply] [d/l] [select] |
|
#!/usr/bin/perl -l
use warnings;
use strict;
my $input = join "|", qw/Monday Saturday Thursday/;
"monday tuesday wednesday thursday friday saturday sunday" =~ m/\b($in
+put)\b(?{ print "[$1]" })(*FAIL)/i;
print join ' ', grep s/,//, split ' ', "monday tuesday wednesday thurs
+day friday saturday sunday" =~ s/\b($input)\b\K/,/igr;
[monday]
[thursday]
[saturday]
monday thursday saturday
| [reply] [d/l] [select] |
|
cool! :)
hm theoretically it should be possible to swap it and generate a (complicated) regex from "monday .. sunday" which sorts the input without explicit sort like the others showed.
But I'm better opting out now! =)
| [reply] |
|
|
|
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by LanX (Saint) on Jul 21, 2022 at 14:27 UTC
|
> is there a way without using that %order?
ehm ... you need this order information somehow.
So is your question
- if this order could be taken from some Date or Time module like DateTime
- or if there is some obfuscated way to calculate it like with the Doomsday algorithm
?
Side note: The week starts traditionally on Sunday. At least for the church. | [reply] |
|
The latter: some kind of algorithm or rather a transform of each weekday into a new name which is alphabetically sorted right (as per the %order or whatever calendar order). For example, transform each weekday by removing the 1st letter, then their cmp order is correct. OK this does not work. But I was looking for this kind of transform. Of course I can try exhaustively find such transform with random masks on the weekday bytes.
monday:011011010110111101101110011001000110000101111001
tuesday:01110100011101010110010101110011011001000110000101111001
wednesday:011101110110010101100100011011100110010101110011011001000110
+000101111001
thursday:0111010001101000011101010111001001110011011001000110000101111
+001
friday:011001100111001001101001011001000110000101111001
saturday:0111001101100001011101000111010101110010011001000110000101111
+001
sunday:011100110111010101101110011001000110000101111001
(with this:
for (qw/monday tuesday wednesday thursday friday saturday sunday/){
print $_ .':'. join('', map { sprintf "%08b", ord($_) } split(//, lc
+$_))."\n";
}
) | [reply] [d/l] [select] |
|
Honestly, I find those magical formulas° always too voodoo.
From a maintenance point of view they are horrible, because they don't scale well with new requirements.
Even Doomsday fails if you go back before Gregorian calendar
°) don't know the correct term here... ³
update
there is only a limited number of orders 7!
so you could try a brute force search composing formulas based on inputs like substrings or word-length.
I'm still not sure if the solution will be shorter than just a clever list.²
update
²) tybaldt's solution with "motuwethfrsasu" is just an example of such a clever list.
³) kind of golfing, isn't it?
| [reply] [d/l] [select] |
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by AnomalousMonk (Archbishop) on Jul 25, 2022 at 02:19 UTC
|
Another approach. Not necessarily better, but anyway... An %order hash is still needed to encapsulate day order. No modules or regex matching involved. (The code is presented in a very simple module for convenience of testing and presentation, but module encapsulation is not essential.) Day order is Sunday - Saturday and can only be changed by changing the code. Encoding of day order value is 0 .. 6 per the C tm structure tm_wday element.
This approach depends on the fact that "short" weekday names like 'mon' are all present as left-anchored substrings of the "long" names, e.g., 'monday'. Unfortunately, this leads to false-positives such as 's' matching Sunday and 'mond' matching Monday. OTOH, variations like th/thu/thur/thurs/thursday all match correctly.
File CmpDay.pm:
File CmpDay.t:
Output:
Win8 Strawberry 5.8.9.5 (32) Sun 07/24/2022 21:31:02
C:\@Work\Perl\monks\bliako
>perl CmpDay.t
ok 1 - use CmpDay;
#
# === testing under perl version 5.008009 ===
#
1..41
# invalid weekday names (no wday numbers)
ok 2 - '' -> undef
ok 3 - 'x' -> undef
ok 4 - 'xyz' -> undef
ok 5 - 'xsun' -> undef
ok 6 - 'sunx' -> undef
ok 7 - 'xsunx' -> undef
ok 8 - 'mondaytuesday' -> undef
ok 9 - 'mondayxtuesday' -> undef
ok 10 - 'sunsun' -> undef
# valid weekday names -> wday numbers
ok 11 - 'su' -> 0
ok 12 - 'sun' -> 0
ok 13 - 'sunday' -> 0
ok 14 - 'sU' -> 0
ok 15 - 'Su' -> 0
ok 16 - 'SU' -> 0
ok 17 - 'sUnDaY' -> 0
ok 18 - 'we' -> 3
ok 19 - 'wed' -> 3
ok 20 - 'wednesday' -> 3
ok 21 - 'wE' -> 3
ok 22 - 'We' -> 3
ok 23 - 'WE' -> 3
ok 24 - 'WednEsDaY' -> 3
ok 25 - 'sa' -> 6
ok 26 - 'sat' -> 6
ok 27 - 'saturday' -> 6
ok 28 - 'sA' -> 6
ok 29 - 'Sa' -> 6
ok 30 - 'SA' -> 6
ok 31 - 'sAtUrDaY' -> 6
# invalid weekday numbers (no corresponding wday name)
ok 32 - 7 -> undef
ok 33 - -8 -> undef
# valid weekday numbers -> wday names
ok 34 - 0 -> "sunday"
ok 35 - -7 -> "sunday"
ok 36 - 3 -> "wednesday"
ok 37 - -4 -> "wednesday"
ok 38 - 6 -> "saturday"
ok 39 - -1 -> "saturday"
#
# test sorting of mixed short/long day names
#
ok 40 - shuffled day names
#
# === testing done ===
#
ok 41 - no warnings
Give a man a fish: <%-{-{-{-<
| [reply] [d/l] [select] |
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by kcott (Archbishop) on Jul 26, 2022 at 14:05 UTC
|
G'day bliako,
Here's another way:
enum for the order; and, an Orcish Manoeuvre for efficiency.
#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use enum qw{sun mon tue wed thu fri sat};
say '*** Check Orcish Manoeuvre is working ***';
say _canon_day_test($_) for qw{Mon mon Monday monday} x2;
say '*** Your sort example ***';
my @weekdays = qw/Monday Saturday Thursday/;
say for sort { _canon_day($a) <=> _canon_day($b) } @weekdays;
say '*** More complex example ***';
my @many_form_weekdays = qw{
thurs tue Thu Tues Thursday tuesday
Fri Sun sat Fri Sun sat SATURDAY FRIDAY SUNDAY
Wednesday Mon wed monday
sun Sat friday Friday Sunday
};
say for sort { _canon_day($a) <=> _canon_day($b) } @many_form_weekdays
+;
sub _canon_day {
my ($day) = @_;
state $day_for = {};
return $day_for->{$day} ||= eval lc substr $day, 0, 3;
}
sub _canon_day_test {
my ($day) = @_;
state $day_for = {};
say "'$day' needs Orc" unless exists $day_for->{$day};
return $day_for->{$day} ||= eval lc substr $day, 0, 3;
}
_canon_day_test() is identical to _canon_day() except for the say statement:
it's just for testing.
You may want to add some validation code, but that wasn't part of your question.
Output:
*** Check Orcish Manoeuvre is working ***
'Mon' needs Orc
1
'mon' needs Orc
1
'Monday' needs Orc
1
'monday' needs Orc
1
1
1
1
1
*** Your sort example ***
Monday
Thursday
Saturday
*** More complex example ***
Sun
Sun
SUNDAY
sun
Sunday
Mon
monday
tue
Tues
tuesday
Wednesday
wed
thurs
Thu
Thursday
Fri
Fri
FRIDAY
friday
Friday
sat
sat
SATURDAY
Sat
| [reply] [d/l] [select] |
|
I have trouble finding a canonical explanation of Orcish Manoeuvre, but isn't Memoize faster in this case?
| [reply] |
|
G'day Rolf,
"I have trouble finding a canonical explanation of Orcish Manoeuvre, ..."
"A Fresh Look at Efficient Perl Sorting"
describes many sorting techniques.
The section on OM points to a footnote with details of a book by the inventor of this algorithm.
I don't own, nor have I read, this book, so I can't comment further.
"... but isn't Memoize faster in this case?"
Try Benchmark to answer that.
Please post your results:
I, and no doubt others, would be interested.
| [reply] |
|
OM is basically ST, but where the sort is provided the default comparison function ($a cmp $b).
Technically, any of the four builtin compare functions would work equally fast.
- $a cmp $b
- $b cmp $a
- $a <=> $b
- $b <=> $a
| [reply] [d/l] [select] |
|
| [reply] |
|
| [reply] |
|
Re: Challenge: sort weekdays in week-order (elegantly and efficiently)
by ikegami (Patriarch) on Jul 26, 2022 at 14:15 UTC
|
Same approach you took, but clearer and faster:
use Sort::Key qw( ikeysort );
my @sorted = ikeysort { $order{ fc( $_ ) } } @unsorted;
| [reply] [d/l] |
|
| [reply] [d/l] |
|
| [reply] |