s/// bzw. y/// in map
am 17.08.2007 09:37:47 von Christian Garbs
Mahlzeit!
Ich möchte in einer Liste für jedes Element eine Ersetzung
durchführen. Als problematisch hat sich dabei herausgestellt, dass
der Rückgabewert der Ersetzung im skalaren Kontext die Anzahl der
Ersetzungen ist und nicht das veränderte Listenelement.
Ich habe mir jetzt folgendermaÃen beholfen:
#!/usr/bin/perl -w
use strict;
my @arr = qw( test eins zwei drei );
@arr = map { ($_ =~ y/e/X/, $_)[1] } @arr;
print "$_\n" foreach @arr;
Das mit dem ($_ =~ y/e/X/, $_)[1] kommt mir nicht sehr elegant vor.
Geht das anders/besser/schöner, wenn ich darauf bestehe, das mit map
lösen zu wollen?
(Ohne map sieht ein y/e/X/ foreach (@arr); ganz schnuckelig aus.)
GruÃ,
Christian
--
sub _{print"\n"}_;for(;$s<9;++$s){$_='1E2018201E00001E2018201E00001E2018201'
..'E002020001C2222221400005CA2A2A27C02001C2222221C20003E0402 02201F2422221C00'
..'242A2A2A12002020001C2222221F20001C2A2A2A0C';while(s;(..); ;){printf'%c',hex
$1&1<<$s?40:32}_}$_=':::Christian Garbs:',y;:;\t;;print;_;_
Re: s/// bzw. y/// in map
am 17.08.2007 09:48:05 von Bjoern Hoehrmann
* Christian Garbs wrote in de.comp.lang.perl.misc:
>Ich möchte in einer Liste für jedes Element eine Ersetzung
>durchführen. Als problematisch hat sich dabei herausgestellt, dass
>der Rückgabewert der Ersetzung im skalaren Kontext die Anzahl der
>Ersetzungen ist und nicht das veränderte Listenelement.
Das ist im Arraykontext nicht anders...
>my @arr = qw( test eins zwei drei );
>@arr = map { ($_ =~ y/e/X/, $_)[1] } @arr;
In erster Näherung kannst du das als
@arr = map { y/e/X/; $_ } @arr;
schreiben. Natürlich ist das nichts anderes als einfach nur
map y/e/X/, @arr;
da du ja $_ direkt veränderst.
--
Björn Höhrmann · mailto:bjoern@hoehrmann.de · http://bjoern.hoehrmann.de
Weinh. Str. 22 · Telefon: +49(0)621/4309674 · http://www.bjoernsworld.de
68309 Mannheim · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/
Re: s/// bzw. y/// in map
am 17.08.2007 11:54:02 von Christian Winter
Christian Garbs schrieb:
> Mahlzeit!
>
> Ich möchte in einer Liste für jedes Element eine Ersetzung
> durchführen. Als problematisch hat sich dabei herausgestellt, dass
> der Rückgabewert der Ersetzung im skalaren Kontext die Anzahl der
> Ersetzungen ist und nicht das veränderte Listenelement.
>
> Ich habe mir jetzt folgendermaÃen beholfen:
>
> #!/usr/bin/perl -w
> use strict;
> my @arr = qw( test eins zwei drei );
> @arr = map { ($_ =~ y/e/X/, $_)[1] } @arr;
> print "$_\n" foreach @arr;
>
> Das mit dem ($_ =~ y/e/X/, $_)[1] kommt mir nicht sehr elegant vor.
> Geht das anders/besser/schöner, wenn ich darauf bestehe, das mit map
> lösen zu wollen?
>
> (Ohne map sieht ein y/e/X/ foreach (@arr); ganz schnuckelig aus.)
Nimm for(), das gibt Dir Aliase auf die echten Elemente
(was zwar auch map{} macht, aber damit kreierst Du überflüssige
temporäre Listen), so dass Ersetzungen in $_ jeweils auf das
momentane Array-Element selbst wirken.
--------------------------------------
my @arr = qw( test eins zwei drei );
y/e/X/ for( @arr );
print $_.$/ for( @arr );
tXst
Xins
zwXi
drXi
--------------------------------------
-Christian
Re: s/// bzw. y/// in map
am 17.08.2007 13:52:55 von Ingo Menger
On 17 Aug., 11:54, Christian Winter wrote:
> Christian Garbs schrieb:
> > (Ohne map sieht ein y/e/X/ foreach (@arr); ganz schnuckelig aus.)
>
> Nimm for(), das gibt Dir Aliase auf die echten Elemente
> (was zwar auch map{} macht, aber damit kreierst Du überflüssige
> temporäre Listen),
Ob die überflüssig sind, kann man nicht generell sagen.
Wenn, dann räumt sie der GC weg.
Wenn nicht, dann zwingt einen dieser Stil zu explizit hingeschriebenen
Kopien oder Inkaufnahme von u.U. schwer zu druchschauendem Verhalten.
Re: s/// bzw. y/// in map
am 17.08.2007 14:51:56 von Ferry Bolhar
Christian Garbs:
> Das mit dem ($_ =~ y/e/X/, $_)[1] kommt mir nicht sehr elegant vor.
> Geht das anders/besser/schöner, wenn ich darauf bestehe, das mit map
> lösen zu wollen?
Aber ja.
Innerhalb vom map ist $_ ein Alias auf jedes Element der Liste.
Veränderst du es irgendwie, veränderst du das jeweilige Listenelement.
Daher ist die Array-Zuweisung letztlich überflüssig:
map tr/e/X/, @arr;
(Ich verwende lieber 'tr', aber das ist Geschmackssache).
> print "$_\n" foreach @arr;
print join "\n", @arr, '';
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: s/// bzw. y/// in map
am 23.08.2007 22:52:46 von Christian Garbs
Mahlzeit!
Bjoern Hoehrmann wrote:
> schreiben. Natürlich ist das nichts anderes als einfach nur
>
> map y/e/X/, @arr;
>
> da du ja $_ direkt veränderst.
Prima, das war jetzt die Klarstellung, die mir den Komma-Separator
nähergebracht hat (und steht wahrscheinlich doch genau so in perldoc).
GruÃ,
Christian
--
sub _{print"\n"}_;for(;$s<9;++$s){$_='1E2018201E00001E2018201E00001E2018201'
..'E002020001C2222221400005CA2A2A27C02001C2222221C20003E0402 02201F2422221C00'
..'242A2A2A12002020001C2222221F20001C2A2A2A0C';while(s;(..); ;){printf'%c',hex
$1&1<<$s?40:32}_}$_=':::Christian Garbs:',y;:;\t;;print;_;_
Re: s/// bzw. y/// in map
am 23.08.2007 22:53:26 von Christian Garbs
Mahlzeit!
Ferry Bolhar wrote:
>> print "$_\n" foreach @arr;
>
> print join "\n", @arr, '';
Das merk ich mir!
(Ist zwar kein Zeichen kürzer, aber irgendwie eleganter.)
GruÃ,
Christian
--
sub _{print"\n"}_;for(;$s<9;++$s){$_='1E2018201E00001E2018201E00001E2018201'
..'E002020001C2222221400005CA2A2A27C02001C2222221C20003E0402 02201F2422221C00'
..'242A2A2A12002020001C2222221F20001C2A2A2A0C';while(s;(..); ;){printf'%c',hex
$1&1<<$s?40:32}_}$_=':::Christian Garbs:',y;:;\t;;print;_;_
Re: s/// bzw. y/// in map
am 25.08.2007 22:04:51 von Ferry Bolhar
"Christian Garbs":
>> print join "\n", @arr, '';
>
> Das merk ich mir!
> (Ist zwar kein Zeichen kürzer, aber irgendwie eleganter.)
Der Code ist effizienter (und dadurch die Abarbeitung schneller),
weil die foreach-Schleife eingespart wird. Allerdings gebe ich gerne
zu, dass sich das heutzutage wohl erst ab einigen tausende Elementen
in @arr spürbar auswirken wird... ;-)
LG, Ferry
--
Re: s/// bzw. y/// in map
am 28.08.2007 10:32:59 von Hendrik Schnepel
This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.
---559023410-851401618-1188289979=:16891
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 8BIT
>>> print join "\n", @arr, '';
>>
>> Das merk ich mir!
>> (Ist zwar kein Zeichen kürzer, aber irgendwie eleganter.)
>
> Der Code ist effizienter (und dadurch die Abarbeitung schneller),
> weil die foreach-Schleife eingespart wird. Allerdings gebe ich gerne
> zu, dass sich das heutzutage wohl erst ab einigen tausende Elementen
> in @arr spürbar auswirken wird... ;-)
Angenommen, ein Geschwindigkeitsunterschied wird bei (sehr) vielen
Elementen bemerkbar, ist es dann nicht eher ineffizienter erstmal einen
moeglicherweise sehr sehr grossen String zu konstruieren, als die ohnehin
bereitstehenden Stuecke einfach direkt auszugeben?
Gruss,
Hendrik
---559023410-851401618-1188289979=:16891--
Re: s/// bzw. y/// in map
am 29.08.2007 14:43:47 von Ferry Bolhar
Hendrik Schnepel:
> Angenommen, ein Geschwindigkeitsunterschied wird bei (sehr) vielen
> Elementen bemerkbar, ist es dann nicht eher ineffizienter erstmal einen
> moeglicherweise sehr sehr grossen String zu konstruieren, als die ohnehin
> bereitstehenden Stuecke einfach direkt auszugeben?
Jede Schleife stellt einen Scope - Geltungsbereich - bereit, der bei deren
Abarbeitung für jeden Durchlauf "betreten" und wieder "verlassen" werden
muss (mittels der OPs "enterloop" und "leaveloop"). Das kostet Zeit.
Im Gegenzug ist das Hinzufügen eines Strings an einen anderen eine
relativ einfache und - solange der Rechnerspeicher nicht zu knapp wird -
auch schnelle Operation. Daher neige ich zu der Annahme, dass der
Code mit "join" der Performantere sein wird, die Variante mit der direkten
Ausgabe hingegen wird sicher weniger Speicher benötigen. Bei einem
angenommenen ausreichend großen Array (so groß, dass überhaupt
Unterschiede bemerkbar werden) dürfte dieser zusätzliche Speicher,
bezogen auf den Platzbedarf für dieses Array, dann allerdings kaum
mehr eine Rolle spielen
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: s/// bzw. y/// in map
am 30.08.2007 22:46:12 von Helmut Wollmersdorfer
Ferry Bolhar wrote:
> Jede Schleife stellt einen Scope - Geltungsbereich - bereit, der bei deren
> Abarbeitung für jeden Durchlauf "betreten" und wieder "verlassen" werden
> muss (mittels der OPs "enterloop" und "leaveloop"). Das kostet Zeit.
Wieviel Zeit?
Nachdem ich vor ein paar Tagen die Behauptung "'for' ist langsam,
deshalb soll man generell 'map' verwenden" mal nachgemessen habe, glaub
ich ohne Benchmark garnix mehr.
Also probieren wir mal:
#!/usr/bin/perl
use strict;
use Benchmark qw(cmpthese);
my @arr = qw{a b r a c a d a b r a};
open (FH, '>', '/dev/null');
cmpthese (
500000, {
'foreach' => sub { print FH "$_\n" foreach @arr; },
'join' => sub { print FH join "\n", @arr, ''; },
});
# Benchmark result (Athlon XP 2500):
Rate foreach join
foreach 136240/s -- -71%
join 471698/s 246% --
Gut, join ist nicht map, und join ist hier dreimal so schnell.
Oder anders ausgedrückt, ein Schleifendurchlauf (pro Listenelement)
kostet ca. 0,5 Millionstel Sekunden.
Wirtschaftlich ausgedrückt, müssen da mal eine Milliarde Elemente
abgearbeitet werden, damit sich die Zeit von 10 Minuten nachdenken
amortisiert hat.
Da hab ich schon eine Applikation, wo sich das rentieren könnte, aber im
Normalfall denke ich über sowas nicht nach. Denn Perl ist verdammt
schnell, wenn man sauberen Code schreibt.
Helmut Wollmersdorfer
Re: s/// bzw. y/// in map
am 30.08.2007 22:57:11 von Ferry Bolhar
"Helmut Wollmersdorfer":
> Da hab ich schon eine Applikation, wo sich das rentieren könnte, aber im
> Normalfall denke ich über sowas nicht nach. Denn Perl ist verdammt
> schnell, wenn man sauberen Code schreibt.
Du hast ja recht. Die Diskussion ist rein akademischer Natur. Aber für
mich ist "sauber" eben auch, wenn ich das Schreiben expliziter Schleifen
vermeiden kann, weil Perl mir bereits implizit einen Schleifenkontext zur
Verfügung stellt, und das wollte ich, als es hier um den Einsatz von "map"
bzw. "foreach" gegegangen ist, kurz anmerken.
LG, Ferry
--
Re: s/// bzw. y/// in map
am 31.08.2007 06:17:52 von Frank Seitz
Helmut Wollmersdorfer wrote:
> Also probieren wir mal:
>
> #!/usr/bin/perl
> use strict;
>
> use Benchmark qw(cmpthese);
>
> my @arr = qw{a b r a c a d a b r a};
>
> open (FH, '>', '/dev/null');
>
> cmpthese (
> 500000, {
> 'foreach' => sub { print FH "$_\n" foreach @arr; },
> 'join' => sub { print FH join "\n", @arr, ''; },
> });
Du misst hier I/O mit, was normalerweise teuer ist.
Die foreach-Variante ist dadurch im Nachteil, da sie
mehr print-Aufrufe produziert, was aber nicht mit dem
Schleifenkonstrukt selbst zu tun hat.
Im Gunde ist die Frage, ob man Zeit oder Platz optimieren will.
Join braucht mehr Platz, die Schleife mehr Zeit.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel