1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
#!/usr/bin/perl use strict; use warnings; use Encode qw(decode); use Unicode::Collate; use String::Random; my $zeilen = 10000; my $spalten = 5; my $methode = 2; ####################################### my %data; for (my $z = 0; $z < $zeilen; $z ++) { my @felder; for (my $s = 0; $s < $spalten; $s ++) { my $d = String::Random::random_string( '10101022',[ split //, uc 'aei' ],[ split //, uc 'bdfghklmnprstwxz' ],[ split //, '23456789' ]); push @felder,$d; # print " $d"; } push @{$data{spalten}},[@felder]; # print "\n"; } print "Daten fertig erzeugt\n"; ####################################### print "\n\nSortiert:\n"; if ($methode == 1) { my $start = time(); my $uniccol = Unicode::Collate->new(); foreach my $harefz ( sort { my $return = 0; my $z = -1; while (!$return && $z < scalar @{$data{spalten}} - 1) { $z ++; $return = $uniccol->cmp($a->[$z],$b->[$z]); } $return; } @{$data{spalten}} ) { for (my $s = 0; $s < scalar @{$harefz}; $s ++) { # print ' '.$harefz->[$s]; } # print "\n"; } print "\nLaufzeit: ".(time()-$start); } else { my $start = time(); foreach my $harefz ( sort { my $return = 0; my $z = -1; while (!$return && $z < scalar @{$data{spalten}} - 1) { $z ++; $return = lc $a->[$z] cmp lc $b->[$z]; } $return; } @{$data{spalten}} ) { for (my $s = 0; $s < scalar @{$harefz}; $s ++) { # print ' '.$harefz->[$s]; } # print "\n"; } print "\nLaufzeit: ".(time()-$start); }
1 2 3
my $uniccol = Unicode::Collate->new(); my @s = sort { $uniccol->cmp($a,$b) } ('Vertrag','Übel','Ärger','Öl','ßig','ärgerlich'); print join(' + ',@s);
1 2
my $uniccol = Unicode::Collate->new(); print join(' + ',sort {$a =~ /[öäüßÖÄÜ]/ || $b =~ /[öäüÄÖÜß]/ ? $uniccol->cmp($a,$b) : lc $a cmp lc $b} ('Vertrag','Übel','Ärger','Öl','ßig','ärgerlich'));
2014-12-28T16:29:05 reneeVielleicht hilft bei Dir ja auch "use locale": http://perldoc.perl.org/locale.html
QuoteRenee + Renée + Vertrag + Ärger + Öl + Übel + ßig + ärgerlich
2014-12-28T16:29:05 reneeIn Robins Blog wurde ja auf https://github.com/tonycoz/Unicode-ICU/tree/master... hingewiesen was schneller sein soll.
Quotecpan> install Unicode::ICU::Collator
Fetching with LWP:
http://cpan.strawberryperl.com/authors/01mailrc.tx...
Fetching with LWP:
http://cpan.strawberryperl.com/modules/02packages....
Fetching with LWP:
http://cpan.strawberryperl.com/modules/03modlist.d...
Database was generated on Thu, 25 Dec 2014 16:21:57 GMT
Updating database file ...
Done!Running install for module 'Unicode::ICU::Collator'
Running make for T/TO/TONYC/Unicode-ICU-Collator-0.002.tar.gz
Fetching with LWP:
http://cpan.strawberryperl.com/authors/id/T/TO/TON...
Fetching with LWP:
http://cpan.strawberryperl.com/authors/id/T/TO/TON...
Checksum for C:\strawberry\cpan\sources\authors\id\T\TO\TONYC\Unicode-ICU-Collator-0.002.tar.gz ok
Scanning cache C:\strawberry\cpan\build for sizes
............................................................................DONE
CPAN.pm: Building T/TO/TONYC/Unicode-ICU-Collator-0.002.tar.gz
Der Befehl "icu-config" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
OS unsupported: No icu-config --cppflags found
Warning: No success on command[C:\strawberry\perl\bin\perl.exe Makefile.PL]
TONYC/Unicode-ICU-Collator-0.002.tar.gz
C:\strawberry\perl\bin\perl.exe Makefile.PL -- NOT OK
Running make test
Make had some problems, won't test
Running make install
Make had some problems, won't install
Stopping: 'install' failed for 'Unicode::ICU::Collator'.
Could not read metadata file. Falling back to other methods to determine prerequisites
Failed during this command:
TONYC/Unicode-ICU-Collator-0.002.tar.gz : writemakefile NO 'C:\strawberry\perl\bin\perl.exe Makefile.PL' returned status 256
1 2
use Encode qw(encode decode); print encode('iso-8859-15',join(' + ',sort {lc $a cmp lc $b} ('Vertrag',decode('windows-1252','Übel'),decode('windows-1252','Ärger'),decode('windows-1252','Renée'),decode('windows-1252','Öl'),decode('windows-1252','ßig'),'Renee',decode('windows-1252','ärgerlich'))));
QuoteRenee + Renée + Vertrag + ßig + Ärger + ärgerlich + Öl + Übel
1 2
use locale; print encode('iso-8859-15',join(' + ',sort {lc $a cmp lc $b} ('Vertrag',decode('windows-1252','Übel'),decode('windows-1252','Ärger'),decode('windows-1252','Renée'),decode('windows-1252','Öl'),decode('windows-1252','ßig'),'Renee',decode('windows-1252','ärgerlich'))));
QuoteRenee + Renée + Vertrag + ßig + Ärger + ärgerlich + Öl + Übel
1 2 3 4
use POSIX qw(locale_h); use locale; setlocale(LC_CTYPE, "de_DE"); print join(' + ',sort {lc $a cmp lc $b} ('Vertrag','Übel','Ärger','Renée','Öl','ßig','Renee','ärgerlich'));
QuoteRenee + Renée + Vertrag + ßig + Ärger + ärgerlich + Öl + Übel
1 2 3 4
use POSIX qw(locale_h); use locale; setlocale(LC_CTYPE, "de"); print join(' + ',sort {lc $a cmp lc $b} ('Vertrag','Übel','Ärger','Renée','Öl','ßig','Renee','ärgerlich'));
QuoteRenee + Renée + Vertrag + Ärger + Öl + Übel + ßig + ärgerlich
1 2
use locale; print join(' + ',sort {lc $a cmp lc $b} ('Vertrag','Übel','Ärger','Renée','Öl','ßig','Renee','ärgerlich'));
QuoteRenee + Renée + Vertrag + Ärger + Öl + Übel + ßig + ärgerlich
$uniccol->cmp($a->[$z],$b->[$z]);
2015-01-02T11:42:00 GUIfreundVersuche doch mal, den Sort durch eine Serie von Sorts über die einzelnen Spalten zu ersetzen, beginnend mit der letzten Spalte
2015-01-02T11:42:00 GUIfreundSchwarzsche Transformation einsetzen
2015-01-02T17:17:12 bianca2015-01-02T11:42:00 GUIfreundVersuche doch mal, den Sort durch eine Serie von Sorts über die einzelnen Spalten zu ersetzen, beginnend mit der letzten Spalte
Das verstehe ich nicht. Was genau meinst du damit?
2015-01-02T17:17:12 biancaAm Ende hab ich jetzt eine Lösung ..... Reicht für meinen Bedarf.
2015-01-04T14:15:53 GUIfreundDein komplexer Vergleichskode hat sich dabei auf einen Einzeiler reduziert.
2015-01-05T07:53:56 bianca2015-01-04T14:15:53 GUIfreundDein komplexer Vergleichskode hat sich dabei auf einen Einzeiler reduziert.
Bitte zeig mir den Einzeler mal kurz. Ich weiß nicht, wie das aussähe, bin sonst mit einem einfachen sort a/b immer hingekommen. Würde hier gern was Neues lernen.
2015-01-05T18:06:44 biancaHmm, aber was ist denn das Neue an Deinem Vorschlag?
2015-01-04T14:15:53 GUIfreundDas dürfte unter'm Strich einen deutlichen Geschwindigkeitsgewinn bringen.
2015-01-05T18:06:44 biancaIch hab ein mehrspaltiges Hash und in zwei Arrays hab ich einmal die Art (nummerisch oder alpha) und im anderen die Reihenfolge (1 = aufwärts und 0 = abwärts) für jede einzelne Spalte.
Wie setze ich denn damit deinen Vorschlag um?
2015-01-06T12:52:20 GUIfreundJede Spalte hat ja ihren eigenen Sort. Für numerische Spalten nimmst du den numerischen Vergleichsoperator <=>, und für abwärts vertauschst du $a und $b (gleich beim Kodieren - bitte kein if). Alles wie gehabt.
2015-01-06T12:52:20 GUIfreundÜbrigens kann es durchaus passieren, dass sich der Geschwindigkeitsgewinn am Ende als gar nicht so berauschend herausstellt. Schließlich benutzt du nach wie vor die Methode $uniccol->cmp. Da könntest du nur auf den Ehrgeiz des Autors hoffen, daran noch zu feilen.
1 2 3 4 5 6 7 8 9 10 11 12
if ($methode == 1) { my $start = time(); my $uniccol = Unicode::Collate->new(); foreach my $z (reverse (0 .. $spalten-1)) { @{$data{spalten}} = sort {$uniccol->cmp($a->[$z],$b->[$z])} @{$data{spalten}}; } # foreach my $feldref (@{$data{spalten}}) { # print "@$feldref\n"; # } print "\nLaufzeit: ".(time()-$start); }
1 2 3 4
use Unicode::Collate; my $alphasorter_modul = Unicode::Collate->new(); my $alphasorter_regex = qr{[^0-9 a-z!"§$%&/()=?\{\[\]\}\]><|_\-+*,.:;#'~\^]}ix; my $sort = sub { $_[0] =~ $alphasorter_regex || $_[1] =~ $alphasorter_regex ? $alphasorter_modul->cmp($_[0],$_[1]) : lc $_[0] cmp lc $_[1] };
Quote$Collator->getSortKey($a) cmp $Collator->getSortKey($b)
is equivalent to
$Collator->cmp($a, $b)
1 2 3 4 5
my @sorted = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, $Collator->getSortKey($_) ] } @zuSortieren;
2015-01-08T08:47:30 RaubtierMan sollte vielleicht nicht von allen Spalten den Key berechnen, wenn man z.B. nie die 2. Spalte vergleicht, wenn z.B. alle 1. Spalten unterschiedlich sind.
1 2 3 4 5 6
use Time::HiRes qw( gettimeofday tv_interval ); my $t0 = [ gettimeofday ]; # your code here print "Time elapsed: " . (tv_interval( $t0 )) . " seconds\n";