Schrift
[thread]11456[/thread]

Eindeutige Liste aller Zeichen im String (Seite 2)

Leser: 1


<< |< 1 2 3 4 >| >> 33 Einträge, 4 Seiten
Gast Gast
 2008-03-12 21:08
#106988 #106988
#!/usr/bin/perl -w

use strict;

my $in = "abcdee3fgh1234eee";
my $out = "";

$out = join("",sort(split("",$in)));
$out =~ tr/0-9a-zA-Z//s;

print "in : $in\n";
print "out: $out\n";
pq
 2008-03-13 00:58
#106991 #106991
User since
2003-08-04
12209 Artikel
Admin1
[Homepage]
user image
and the winner is...
Code (perl): (dl )
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
sub hash1 { 
    my %seen;
    $seen{$_}++ for ( split( //, $string ) );
    my $res = join( '', sort keys %seen );
    return $res;
}

sub hash2 { 
    my $res = $string;
    my %seen;
    $res =~ s/(.)/$seen{$1}++ ? "" : $1/gse;
    return $res;
}

sub joinsplit1 {  
    my $res = join '', split /(.)\1+/, join('', sort( split('', $string )));
}   
    
sub hash3 {
    my $res = join "", sort keys %{ { map{ $_ => 1 } split //, $string } };
}

sub join_tr {
    my $res = join("",sort(split("",$string)));
    $res =~ tr/0-9a-zA-Z//s;
    return $res;
}

use Benchmark;
timethese($ARGV[0] || 100, {
    hash1 => \&hash1,
    hash2 => \&hash2,
    hash3 => \&hash3,
    joinsplit1 => \&joinsplit1,
    join_tr => \&join_tr,
});

Code: (dl )
1
2
3
4
5
6
Benchmark: timing 40000 iterations of hash1, hash2, hash3, join_tr, joinsplit1...
hash1: 1 wallclock secs ( 1.23 usr + 0.00 sys = 1.23 CPU) @ 32520.33/s (n=40000)
hash2: 1 wallclock secs ( 1.11 usr + 0.00 sys = 1.11 CPU) @ 36036.04/s (n=40000)
hash3: 2 wallclock secs ( 1.55 usr + 0.00 sys = 1.55 CPU) @ 25806.45/s (n=40000)
join_tr: 1 wallclock secs ( 0.73 usr + 0.00 sys = 0.73 CPU) @ 54794.52/s (n=40000)
joinsplit1: 1 wallclock secs ( 0.94 usr + 0.00 sys = 0.94 CPU) @ 42553.19/s (n=40000)
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
KurtZ
 2008-03-13 01:10
#106992 #106992
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
Stilistisch gefallen mir Join_tr und der Uniq Vorschlag am besten, wobei die unterschiedliche Qualitäten haben, uniq behält die Ordnung der Elemente bei, während join_tr diese sortiert.

Die Performancespanne von Faktor 2 würd ich in den meisten Fällen vernachlässigen.
TMTOWTDYOG (there's more than one way to dig your own grave)
KurtZ
 2008-03-13 04:24
#106993 #106993
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
Code (perl): (dl )
1
2
3
4
5
6
sub arr2 { 
    my $res = $string;
    my @seen;
    $res =~ s/(.)/$seen[ord($1)]++ ? "" : $1/gse;
    return $res;
}


Arrays sind schneller als Hashes, immerhin Platz 1 im Ranking bei laaaangen Strings.

Code (perl): (dl )
1
2
3
4
5
6
7
sub substr_tr {
        my $res=$string;
        my $out="\0"x256;
        $res =~ s/(.)/substr($out,ord($1),1,$1)/eg;
        $out =~ tr/\0//d;
        return $out;
}


nur (sub)String, auch nicht schneller

Code (perl): (dl )
1
2
3
4
5
sub regex {
        my $res=$string;
        $res =~ s/(.)(?=.*\1)//g;
        return $res;
}


erstaunlich langsam bei langen Strings, linearer Aufwand macht sich bemerkbar....dafür aber echt knapp hingeschrieben.

RegEx Fanatiker können da bestimmt noch tunen...

grübel ... auch nicht schneller:
Code (perl): (dl )
1
2
3
4
5
6
sub regex2 {
        $_=$string;
        my $out="";
        $out.=$1 while ( m/(.)(?!.*\1)/g );
        return $out;
}
TMTOWTDYOG (there's more than one way to dig your own grave)
Strat
 2008-03-13 21:56
#107013 #107013
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
nepos+2008-03-12 18:15:04--
Man kann sich auch mal CPAN:List::MoreUtils ansehen. Da gibts auch eine uniq() Funktion, neben vielen anderen nützlichen Sachen.

Ich empfehle CPAN:List::MoreUtils... gibt nebenbei auch den am besten lesbaren Code.
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
Array
 2008-03-14 13:23
#107044 #107044
User since
2008-02-27
6 Artikel
BenutzerIn
[default_avatar]
Hallo Leute,

zu diesem Thema habe ich auch eine Möglichkeit gefunden:

Code (perl): (dl )
1
2
3
@liste = qw(bla tata uhha lala tata uhha tata uhha bla uhha);
@neu = grep { ! $hash{$_}++} @liste;
print "@neu\n", %hash, "\n";


Meine Frage bezieht sich mehr auf die Funktionsweise dieses Programms!
Wäre nett, wenn mir einer erklären könnte, warum ich mit obigen Programm mehrfache Elemente ausfiltern kann??
Mich würde eine detaillierte Schritt-für-Schritt-Erklärung sehr erfreuen :-). Auch verstehe ich den Einsatz des Negationsoperators ! nicht so ganz...


Schonmal danke für die Antworten.
renee
 2008-03-14 13:41
#107045 #107045
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
grep liefert für alle Werte einer Liste (hier: @liste) die Elemente, für die das letzte Statement im Block (hier: ! $hash{$_}++) wahr ist.

Das grep hier ist im Prinzip folgender Code:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
my @neu = filter_liste();

sub filter_liste{
    my @neu;
    for( @liste ){
        # wenn Ausdruck wahr, dann schiebe das Element in das Array;
        if( ! $hash{$_}++ ){
            push @neu, $_;
        }
    }
    return @neu;
}


$hash{$_}++ zählt für den Schlüssel, der in $_ steht , den Wert um eins nach oben. Wenn der Schlüssel in dem Hash noch nicht existiert, wird er angelegt.

Mal ein Beispielcode:
Code (perl): (dl )
1
2
3
4
5
6
use Data::Dumper;
my %hash;
my @liste = qw(bla tata uhha tata);
for( @liste ){ print Dumper \%hash; $hash{$_}++};

print Dumper \%hash;


Ausgabe:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$VAR1 = {};
$VAR1 = {
'bla' => 1
};
$VAR1 = {
'tata' => 1,
'bla' => 1
};
$VAR1 = {
'uhha' => 1,
'tata' => 1,
'bla' => 1
};
$VAR1 = {
'uhha' => 1,
'tata' => 2,
'bla' => 1
};


Man sieht, dass der Hash am Anfang leer ist und dann wird in jedem Schleifendurchlauf der Schlüssel angelegt und der Wert auf 1 gesetzt (passiert durch das Inkrementieren mit ++). Der Schlüssel "tata" existiert bereits und da wird der Wert auf 2 inkrementiert.

Wichtig ist noch, dass es ein Post-Inkrement ist.

Vgl.:
Code (perl): (dl )
1
2
3
my $val = 0;
print $val++,"\n";
print ++$val;


Ausgabe:
Code: (dl )
1
2
0
2


Beim ersten Versuch wird das Inkrementieren erst nach dem print gemacht (deswegen Post-Inkrement). Also ist $val bei der Ausgabe noch 0 und erst nach dem Statement wird $val auf 1 erhöht. Beim zweiten Versuch ist das ganze ein Prä-Inkrement. Das heißt es wird erst hochgezählt und dann ausgegeben. Deswegen ist $val bei der Ausgabe 2.

Das Post-Inkrement liefert den Wert vor dem Hochzählen. Also liefert $hash{schluessel}++ eine "0" wenn der Schlüssel "schluessel" noch nicht existiert. Durch die Negation (!) wird der Ausdruck bei dem grep "wahr" wenn der Schlüssel noch nicht existiert. Existiert der Schlüssel schon, wird eine "1","2" oder sonst eine positive Zahl (je nachdem wie oft der Schlüssel schon vorkam) und das wäre ja eigentlich "wahr". Durch die Negation wird der Ausdruck aber "falsch" und somit liefert grep in diesem Fall nicht das Element.
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Array
 2008-03-14 16:30
#107059 #107059
User since
2008-02-27
6 Artikel
BenutzerIn
[default_avatar]
Hallo renee,

vielen Dank für Deine perfekte Beschreibung!!!!!
Mir war zu Beginn nicht klar welcher Wert angelegt wird. Jetzt im Nachhinein ist es irgendwie logisch, dass er am Anfang 1 reinschreibt.
Ebenso war ich blöderweise der Meinung nur der Schlüssel würde inkrementiert werden, aber wie soll man z. Bsp. 'tata' inkrementieren?? :-)
Folglich leuchtet mir nun auch die Verwendung des Negationsoperators ! ein.

Jetzt werde ich auch in Zukunft mehr den Befehl Data::Dumper benutzen, um in die Strukturen schauen zu können!

Eine Frage hätte ich noch: Wenn ein beliebiger Befehl nur TRUE oder FALSE zurückliefert, liefert er doch bei TRUE eine 1 zurück. Bei FALSE aber doch keine 0 sondern einen Leerstring, oder?
Man kann aber nicht sagen, dass undefined, 0 und ein Leerstring dasselbe wären, obwohl alle falsch sind? Da habe ich noch ein paar Verständigungsschwierigkeiten.


Ich möchte noch ein Lob auf dieses Forum hier aussprechen! So schnell und v. a. kompetent wird einem selten geholfen!!


Viele Grüße
renee
 2008-03-14 16:42
#107063 #107063
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Array+2008-03-14 15:30:21--
Eine Frage hätte ich noch: Wenn ein beliebiger Befehl nur TRUE oder FALSE zurückliefert, liefert er doch bei TRUE eine 1 zurück. Bei FALSE aber doch keine 0 sondern einen Leerstring, oder?
Man kann aber nicht sagen, dass undefined, 0 und ein Leerstring dasselbe wären, obwohl alle falsch sind? Da habe ich noch ein paar Verständigungsschwierigkeiten.


Was "wahr" und was "falsch" ist, ist in Perl nicht so eindeutig wie in anderen Programmiersprachen. Auch eine "2" ist "wahr" und als "falsch" werden noch mehr Sachen als nur undef, Leerstring und 0 angesehen. Z.B. auch "0E0"...

Code: (dl )
C:\>perl -e "print 'yes' if( 0E0 );


Was Perl intern macht, geht im Prinzip an dieser Stelle schon wieder zu weit. Merken sollte man sich, dass alles was Du genannt hast und alle möglichen Darstellungen von "0" als "falsch" gilt und alles andere als "wahr".

Auch Referenzen (die auch leer sein können) und negative Zahlen, sind "wahr":
Code: (dl )
1
2
3
4
C:\>perl -e "print 'yes' if( {} );"
yes
C:\>perl -e "print 'yes' if(-3);"
yes


Man bekommt mit der Zeit aber ein ziemlich gutes Gefühl dafür, was "wahr" und was "falsch" ist

Für diejenigen, die sich dafür interessieren:

Perl arbeitet bei "falsch" mit einem "sv_no", wie dieser Code zeigt:
Code: (dl )
1
2
3
4
5
6
7
8
C:\>perl -MO=Concise,-exec -e "print !2"
1 <0> enter
2 <;> nextstate(main 1 -e:1) v
3 <0> pushmark s
4 <$> const[SPECIAL sv_no] s
5 <@> print vK
6 <@> leave[1 ref] vKP/REFC
-e syntax OK
und bei "wahr" mit "sv_yes"...
Code: (dl )
1
2
3
4
5
6
7
8
C:\>perl -MO=Concise,-exec -e "print !0"
1 <0> enter
2 <;> nextstate(main 1 -e:1) v
3 <0> pushmark s
4 <$> const[SPECIAL sv_yes] s
5 <@> print vK
6 <@> leave[1 ref] vKP/REFC
-e syntax OK
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
renee
 2008-03-14 16:44
#107064 #107064
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Array+2008-03-14 15:30:21--
[...]
Ebenso war ich blöderweise der Meinung nur der Schlüssel würde inkrementiert werden, aber wie soll man z. Bsp. 'tata' inkrementieren?? :-)


Ach, wenn Du wüsstest, was man in Perl alles machen kann ;-)

Code: (dl )
1
2
C:\>perl -e "my $var = 'tata';print ++$var"
tatb


Quote
Jetzt werde ich auch in Zukunft mehr den Befehl Data::Dumper benutzen, um in die Strukturen schauen zu können!


Das ist ein echt nützliches Modul!
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
<< |< 1 2 3 4 >| >> 33 Einträge, 4 Seiten



View all threads created 2008-03-11 18:39.