Wie leeren String aus Array ausfiltern?

Wie leeren String aus Array ausfiltern?

am 10.04.2006 12:18:21 von frank

Hallo,

ich habe ein Array von Strings, die nach allerlei
per-Element-Manipulationen auch leer sein können. Diese möchte ich
ausfiltern. Wenn es nur das letzte ist (was zum Glück in der Praxis der
Fall ist) kriege ich es hin, aber es muss doch eine allgemeine Lösung
geben?

#!/usr/bin/perl

use strict;
use warnings;

my @testArray = ('hallo','bonjour','');

if ($testArray[-1] eq '') {pop @testArray};

foreach (@testArray) {print;print "\n"};
print "Fertig.\n";

@testArray = ('hallo','','bonjour');

#?

foreach (@testArray) {print;print "\n"};
print "Fertig.\n";

TIA, Frank

--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 13:35:16 von frank

Frank Seitz wrote:

> Frank Küster wrote:
>
>> ich habe ein Array von Strings, die nach allerlei
>> per-Element-Manipulationen auch leer sein können. Diese möchte ich
>> ausfiltern. Wenn es nur das letzte ist (was zum Glück in der Praxis der
>> Fall ist) kriege ich es hin, aber es muss doch eine allgemeine Lösung
>> geben?
>
> Neues Array erzeugen:
> $ perldoc -f grep

Danke, das hilft mir weiter.

> Original manipulieren:
> $ perldoc -f splice

Da sehe ich nicht, wie ich gezielt nur bestimmte Elemente anhand ihres
Inhalts ausfiltern könnte. Es geht ja gerade darum, von der Position
unabhängig zu werden.

@Daniel: Das war ja nur ein Minimalbeispiel, "in echt" wird mehrfach
über die Elemente der Liste iteriert, und es wäre ineffizient, den Test
jedesmal hinzuschreiben - also lieber einmal filtern.

Danke, Frank
--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 13:38:35 von Frank Seitz

Frank Küster wrote:

> ich habe ein Array von Strings, die nach allerlei
> per-Element-Manipulationen auch leer sein können. Diese möchte ich
> ausfiltern. Wenn es nur das letzte ist (was zum Glück in der Praxis der
> Fall ist) kriege ich es hin, aber es muss doch eine allgemeine Lösung
> geben?

Neues Array erzeugen:
$ perldoc -f grep

Original manipulieren:
$ perldoc -f splice

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

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 13:49:00 von Ingo Menger

Frank Küster schrieb:

> Hallo,
>
> ich habe ein Array von Strings, die nach allerlei
> per-Element-Manipulationen auch leer sein können. Diese möchte ich
> ausfiltern. Wenn es nur das letzte ist (was zum Glück in der Praxis der
> Fall ist) kriege ich es hin, aber es muss doch eine allgemeine Lösung
> geben?

grep { defined $_ and length $_ > 0 } @strings

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 13:55:47 von Daniel Tiefnig

Frank Küster wrote:
> @testArray = ('hallo','','bonjour');

> foreach (@testArray) {print;print "\n"};

Abgesehen von Franks Antwort, wenn es nur um das vorliegende Beispiel
geht läßt es sich auch ganz einfach bei der Ausgabe filtern:

foreach (@testArray) {print $_, "\n" unless $_ eq ''};

lg,
daniel

PS: Golfer schreiben vermutlich lieber:
/./&&print"$_\n"for@testArray;

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 14:00:20 von Mirco Wahab

Hallo Frank,

> ich habe ein Array von Strings, die nach allerlei
> [leere strings ausfiltern]
> Wenn es nur das letzte ist (was zum Glück in der Praxis der
> Fall ist) kriege ich es hin,

Dann mach es doch so ;-)
Setze die "leeren" ans Ende:

my @testArray = ( '', '', 'hallo', '', '', 'bonjour', '', '');

my @otherArray = reverse sort @testArray; # alle Leeren ans Ende

jetzt behandelst Du @otherArray, so, wie
Du's kannst ...

Viele Grüße

Mirco

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 17:15:50 von Frank Seitz

Frank Küster wrote:
> Frank Seitz wrote:
>>
>>Original manipulieren:
>>$ perldoc -f splice
>
> Da sehe ich nicht, wie ich gezielt nur bestimmte Elemente anhand ihres
> Inhalts ausfiltern könnte. Es geht ja gerade darum, von der Position
> unabhängig zu werden.

Mit der Funktion kannst Du ein Element *irgendwo* aus
einem Array entfernen. Wie Du damit die Aufgabe löst, überlasse
ich Dir als Übungsaufgabe.

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

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 18:01:59 von David Haller

Frank Küster wrote:
> ich habe ein Array von Strings, die nach allerlei
> per-Element-Manipulationen auch leer sein können. Diese möchte ich
> ausfiltern.

$ perl -we 'use strict;
my @A = ("hallo", "", "bonjour", undef, "", "hola");
@A = grep($_, @A); print "$_\n" for @A;'

Nur Ausgabe:

$ perl -we 'use strict;
my @A = ("hallo", "", "bonjour", undef, "", "hola");
print "$_\n" for grep($_,@A);'

HTH,
-dnh

--
It's so nice to be insane, no one asks you to explain!

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 18:40:18 von Ingo Menger

Mirco Wahab schrieb:


> my @otherArray =3D reverse sort @testArray; # alle Leeren ans Ende

s/reverse sort/sort {$b cmp $a}/

(reverse ist unnötig teuer, besonders bei großen Arrays)

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 20:19:24 von David Haller

Ingo Menger wrote:
> Mirco Wahab schrieb:
>> my @otherArray = reverse sort @testArray; # alle Leeren ans Ende
>
> s/reverse sort/sort {$b cmp $a}/
>
> (reverse ist unnötig teuer, besonders bei großen Arrays)

Warum ueberhaupt ans Ende?

@testArray = sort @testArray;
shift @testArray while( ! $testArray[0] );

Das sort meckert aber, wenn ein 'undef' im Array auftaucht. Da ist das
'grep' dann wohl besser.

-dnh

--
Bei Deiner alten SuSE war so ein rechteckiges Ding aus totem Baum
dabei. Man nennt es Handbuch.
[Stefan Tomaneck in de.comp.os.unix.linux]

Re: Wie leeren String aus Array ausfiltern?

am 10.04.2006 20:28:25 von Mirco Wahab

Hallo Ingo

>> my @otherArray = reverse sort @testArray; # alle Leeren ans Ende
>
> s/reverse sort/sort {$b cmp $a}/
>
> (reverse ist unnötig teuer, besonders bei großen Arrays)

ich denke mal, das war schon früher so, wie Du sagst.
Aber:


...
As of version 5.8.6, Perl recognises the _reverse sort_ and
does it _without_ generating the temporary, intermediate list.
...


(Quelle: Schwartz, d foy, Phoenix: "Intermediate Perl", O'Reilly 2006, p. 90)

D.h., das prägnante Idiom 'reverse sort' ist
jetzt nicht nur aufgrund seiner Klarheit -
sondern auch aufgrund seiner Performance
einsetzbar.

Viele Grüße

Mirco

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 08:30:20 von frank

Frank Seitz wrote:

> Frank Küster wrote:
>> Frank Seitz wrote:
>>>
>>>Original manipulieren:
>>>$ perldoc -f splice
>>
>> Da sehe ich nicht, wie ich gezielt nur bestimmte Elemente anhand ihres
>> Inhalts ausfiltern könnte. Es geht ja gerade darum, von der Position
>> unabhängig zu werden.
>
> Mit der Funktion kannst Du ein Element *irgendwo* aus
> einem Array entfernen.

Das ist schon klar, aber es kommt mir nicht sehr effizient vor, erst
über den Array zu iterieren, um die auszufilternden Elemente zu finden,
und hinterher für jedes gefundene splice aufzurufen. Warum nicht
einfach

@oldarray = grep {! /pattern } @oldarray

Gruß, Frank
--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 08:31:09 von frank

David Haller wrote:

> Ingo Menger wrote:
>> Mirco Wahab schrieb:
>>> my @otherArray = reverse sort @testArray; # alle Leeren ans Ende
>>
>> s/reverse sort/sort {$b cmp $a}/
>>
>> (reverse ist unnötig teuer, besonders bei großen Arrays)
>
> Warum ueberhaupt ans Ende?
>
> @testArray = sort @testArray;
> shift @testArray while( ! $testArray[0] );
>
> Das sort meckert aber, wenn ein 'undef' im Array auftaucht.

Ich habe aber gar kein undef, sondern ''.

Gruß, Frank
--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 08:34:35 von frank

David Haller wrote:

> Frank Küster wrote:
>> ich habe ein Array von Strings, die nach allerlei
>> per-Element-Manipulationen auch leer sein können. Diese möchte ich
>> ausfiltern.
>
> $ perl -we 'use strict;
> my @A = ("hallo", "", "bonjour", undef, "", "hola");
> @A = grep($_, @A); print "$_\n" for @A;'

Ah, das ist nett.

TIA, Frank

--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 10:22:35 von Frank Seitz

Frank Küster wrote:
> Frank Seitz wrote:

>>>>Original manipulieren:
>>>>$ perldoc -f splice
>>>
>>>Da sehe ich nicht, wie ich gezielt nur bestimmte Elemente anhand ihres
>>>Inhalts ausfiltern könnte. Es geht ja gerade darum, von der Position
>>>unabhängig zu werden.
>>
>>Mit der Funktion kannst Du ein Element *irgendwo* aus
>>einem Array entfernen.
>
> Das ist schon klar, aber es kommt mir nicht sehr effizient vor, erst
> über den Array zu iterieren, um die auszufilternden Elemente zu finden,
> und hinterher für jedes gefundene splice aufzurufen. Warum nicht
> einfach
>
> @oldarray = grep {! /pattern } @oldarray

grep() hatte ich als erste Möglichkeit vorgeschlagen.
Eine Lösung mit splice() halte ich im Gegensatz zu Dir
für effizienter, da grep() ein neues Array aufbaut
und Daten kopiert, während splice() nur wegwirft.

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

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 10:25:44 von Frank Seitz

Frank Küster wrote:
> David Haller wrote:
>>
>>$ perl -we 'use strict;
>>my @A = ("hallo", "", "bonjour", undef, "", "hola");
>>@A = grep($_, @A); print "$_\n" for @A;'
>
> Ah, das ist nett.

Ist aber nicht wirklich sicher.
Denn der Code filtert auch '0', nicht nur ''.

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

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 11:20:56 von Ingo Menger

Mirco Wahab schrieb:

> Hallo Ingo
>
> >> my @otherArray =3D reverse sort @testArray; # alle Leeren ans Ende
> >
> > s/reverse sort/sort {$b cmp $a}/
> >
> > (reverse ist unnötig teuer, besonders bei großen Arrays)
>
> ich denke mal, das war schon früher so, wie Du sagst.
> Aber:
>
>
> ...
> As of version 5.8.6, Perl recognises the _reverse sort_ and
> does it _without_ generating the temporary, intermediate list.
> ...
>

>
> (Quelle: Schwartz, d foy, Phoenix: "Intermediate Perl", O'Reilly 2006, p.=
90)

Cool. Wußte ich nicht.


> D.h., das prägnante Idiom 'reverse sort' ist
> jetzt nicht nur aufgrund seiner Klarheit -
> sondern auch aufgrund seiner Performance
> einsetzbar.

Um so besser.
Prinzipiell könnte man das wohl öfters machen, z.B. reverse map,
reverse grep, usw.
Selbst bei reverse map {..} grep {...} map {...} o.ä.
Die entsprechende Technik heißt in funktionalen Sprachen
"deforestation" (Eliminierung von Listen, die nur Zwischenergebnisse
sind), glaube ich.

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 11:51:54 von frank

Frank Seitz wrote:

> Frank Küster wrote:
>> Frank Seitz wrote:
>
>>>>>Original manipulieren:
>>>>>$ perldoc -f splice
>>>>
>>>>Da sehe ich nicht, wie ich gezielt nur bestimmte Elemente anhand ihres
>>>>Inhalts ausfiltern könnte. Es geht ja gerade darum, von der Position
>>>>unabhängig zu werden.
>>>
>>>Mit der Funktion kannst Du ein Element *irgendwo* aus
>>>einem Array entfernen.
>>
>> Das ist schon klar, aber es kommt mir nicht sehr effizient vor, erst
>> über den Array zu iterieren, um die auszufilternden Elemente zu finden,
>> und hinterher für jedes gefundene splice aufzurufen. Warum nicht
>> einfach
>>
>> @oldarray = grep {! /pattern } @oldarray
>
> grep() hatte ich als erste Möglichkeit vorgeschlagen.
> Eine Lösung mit splice() halte ich im Gegensatz zu Dir
> für effizienter, da grep() ein neues Array aufbaut
> und Daten kopiert, während splice() nur wegwirft.

Dann verstehe ich immer noch nicht, wie ich splice verwenden soll. Oder
doch, meinst du so:

#!/usr/bin/perl

use strict;
use warnings;

my @testArray = ('hallo','','bonjour','trulalla','','bye');
print "@testArray.\n";

my $i=0;
foreach (@testArray) {
if (/(^$)/) { splice(@testArray,$i,1) }
$i++;
};
print "@testArray\n";

TIA, Frank

--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 17:11:02 von Frank Seitz

Frank Küster wrote:

> Dann verstehe ich immer noch nicht, wie ich splice verwenden soll. Oder
> doch, meinst du so:
>
> #!/usr/bin/perl
>
> use strict;
> use warnings;
>
> my @testArray = ('hallo','','bonjour','trulalla','','bye');
> print "@testArray.\n";
>
> my $i=0;
> foreach (@testArray) {
> if (/(^$)/) { splice(@testArray,$i,1) }
> $i++;
> };
> print "@testArray\n";

So ungefähr, nur dass Du erstens eine klassische for-Schleife
anstelle von foreach nehmen solltest. Grund:

| "foreach" will get very confused if
| you add or remove elements within the loop body, for example with
| "splice". So don't do that.

Und zweitens lieber ... eq '' testen solltest. Der Pattern-Match
ist für den Test nicht nötig und auch nicht ganz richtig.
Er matcht neben '' auch "\n".

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

Re: Wie leeren String aus Array ausfiltern?

am 11.04.2006 17:25:12 von frank

Frank Seitz wrote:

> So ungefähr, nur dass Du erstens eine klassische for-Schleife
> anstelle von foreach nehmen solltest. Grund:
>
> | "foreach" will get very confused if
> | you add or remove elements within the loop body, for example with
> | "splice". So don't do that.

Ah, ich hatte genau aus diesem Grund ein ungutes Gefühl mit der
Schleife, aber ich wusste überhaupt nicht, dass sich for und foreach
unterschiedlich verhalten - ich dachte es seien einfach Synonyme. Das
steht ja so auch in perlsyn, und zwei Absätze später kommt dann die von
dir zitierte Warnung...

Gruß und Dank,
Frank
--
> ich wusste mal einen Befehl, der die Ausgabe auf stdout noch zusätzlich
> in eine Datei umlenken konnte... Bitte helft mir auf die Sprünge.
"kaffee" war es nicht.

Re: Wie leeren String aus Array ausfiltern?

am 12.04.2006 03:12:26 von Joerg Plate

> So ungefähr, nur dass Du erstens eine klassische for-Schleife anstelle von foreach nehmen solltest.

Seit wann unterscheiden sich "for" und "foreach"...?


1> perldoc perlsyn
[..]
The "foreach" keyword is actually a synonym for the "for" keyword


(hardcore loesung: lesen von toke.c)
--
"I'm working on it."

Re: Wie leeren String aus Array ausfiltern?

am 12.04.2006 09:27:00 von Frank Seitz

Joerg Plate wrote:
>>So ungefähr, nur dass Du erstens eine klassische for-Schleife
>>anstelle von foreach nehmen solltest.
>
> Seit wann unterscheiden sich "for" und "foreach"...?
>
> 1> perldoc perlsyn
> [..]
> The "foreach" keyword is actually a synonym for the "for" keyword
>
> (hardcore loesung: lesen von toke.c)

Ich meinte mit "klassische for-Schleife" sowas:

for (my $i = $#arr; $i >= 0; $i--) ...

Das ist schon ein ganz anderes Konstrukt, auch wenn
es mit demselben Schlüsselwort eingeleitet wird.

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

Re: Wie leeren String aus Array ausfiltern?

am 12.04.2006 22:30:19 von Slaven Rezic

Frank Seitz writes:

> Frank Küster wrote:
> > Frank Seitz wrote:
>
> >>>>Original manipulieren:
> >>>>$ perldoc -f splice
> >>>
> >>>Da sehe ich nicht, wie ich gezielt nur bestimmte Elemente anhand ihres
> >>>Inhalts ausfiltern könnte. Es geht ja gerade darum, von der Position
> >>>unabhängig zu werden.
> >>
> >>Mit der Funktion kannst Du ein Element *irgendwo* aus
> >>einem Array entfernen.
> >
> > Das ist schon klar, aber es kommt mir nicht sehr effizient vor, erst
> > über den Array zu iterieren, um die auszufilternden Elemente zu finden,
> > und hinterher für jedes gefundene splice aufzurufen. Warum nicht
> > einfach
> >
> > @oldarray = grep {! /pattern } @oldarray
>
> grep() hatte ich als erste Möglichkeit vorgeschlagen.
> Eine Lösung mit splice() halte ich im Gegensatz zu Dir
> für effizienter, da grep() ein neues Array aufbaut
> und Daten kopiert, während splice() nur wegwirft.

Was in Perl effizient ist oder nicht, ist eigentlich nur durch
Benchmarks zu erfahren. Und oft gilt das Ergebnis nur für ein
(Betriebs-)System und eine Perl-Konfiguration und nur für bestimmte
Eingabedaten.

Eine Lösung mit splice() hat den Vorteil, dass nicht mehr Speicher als
am Anfang verwendet wird, während bei grep() Speicherplatz für sowohl
Ergebnis- als auch Argumentliste gleichzeitig benötigt wird. Bei
splice() muss allerdings auch kopiert werden, da es sich bei
Perl-Arrays um echte Arrays und nicht um Listen handelt. Die Lösung
mit grep() könnte bei der Anzahl der aufgerufenen Opcodes aber
effizienter sein.

Gruß,
Slaven

--
Slaven Rezic - slaven rezic de

tktimex - time recording tool
http://sourceforge.net/projects/ptktools/

Re: Wie leeren String aus Array ausfiltern?

am 13.04.2006 08:57:41 von Frank Seitz

Slaven Rezic wrote:
> Frank Seitz writes:
>>Frank Küster wrote:
>>>
>>>@oldarray = grep {! /pattern } @oldarray
>>
>>grep() hatte ich als erste Möglichkeit vorgeschlagen.
>>Eine Lösung mit splice() halte ich im Gegensatz zu Dir
>>für effizienter, da grep() ein neues Array aufbaut
>>und Daten kopiert, während splice() nur wegwirft.
>
> Was in Perl effizient ist oder nicht, ist eigentlich nur durch
> Benchmarks zu erfahren.

Was die Ausführungszeit angeht, auf jeden Fall.
Ich habe wohlweißlich gesagt, dass ich es für effizienter halte,
nicht dass es effizienter ist.
Effizienz schließt für mich übrigens Zeit *und* Platz ein.

> Und oft gilt das Ergebnis nur für ein
> (Betriebs-)System und eine Perl-Konfiguration und nur für bestimmte
> Eingabedaten.

Bei den allgemeinen Datenstrukturen und ihren Grundoperationen
rechne ich nicht mit großartigen Variationen.

> Eine Lösung mit splice() hat den Vorteil, dass nicht mehr Speicher als
> am Anfang verwendet wird, während bei grep() Speicherplatz für sowohl
> Ergebnis- als auch Argumentliste gleichzeitig benötigt wird.

Das war auch mein Hauptgedanke.

> Bei splice() muss allerdings auch kopiert werden, da es sich bei
> Perl-Arrays um echte Arrays und nicht um Listen handelt.

Schon richtig. Aber das dürften ultraschnelle Verschiebeoperationen
von zusammenhängendem Speicher sein, die maschinennah
ausgeführt werden.

> Die Lösung
> mit grep() könnte bei der Anzahl der aufgerufenen Opcodes aber
> effizienter sein.

Gut möglich, dass das Iterieren auf Perl-Ebene in der
slice()-Variante vergleichsweise teuer kommt.

Wer probiert es mal aus?

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

Re: Wie leeren String aus Array ausfiltern?

am 13.04.2006 11:13:16 von Ingo Menger

Slaven Rezic schrieb:

> Eine Lösung mit splice() hat den Vorteil, dass nicht mehr Speicher als
> am Anfang verwendet wird, während bei grep() Speicherplatz für sowohl
> Ergebnis- als auch Argumentliste gleichzeitig benötigt wird.

Ist klar.
Man muß aber auch die semantische Sauberkeit der Lösung in die
Waagschale werfen, gegen ein paar MB billigen Speicher.
Die Aufgabe war ja, abstrakt formuliert:
- ich will die Elemente der Liste mit Eigenschaft E

Mit der splice-Lösung machst Du aber in Wirklichkeit:
- entferne die Elemente aus der Liste, die nicht die Eigenschaft E
haben.

Sie wird somit sofort untauglich, wenn es mir später einfällt, daß
ich außerdem auch noch die Elemente der Ausgangsliste mit Eigenschaft
E2 brauche. Denn dann sind alle Elemente, die Eigenschaft E2, aber
nicht Eigenschaft E haben, gar nicht mehr da.
Die splice-Lösung taugt somit nur als Hack in äußerster Speichernot
unter der Bedingung, daß die Originalliste nicht mehr gebraucht wird.
Zudem kann sie auch durchaus noch langsamer sein, v.a. auf Rechnern mit
gutem Cache und natürlich abhängig von der Größe der Liste.
Weiß jemand, ob man in Perl6 Datenobjekte wie Arrays als nicht muatble
kennzeichnen können wird? Dann könnten grep, map usw. auf solchen
Arrays lazy ablaufen und man spart dann in vielen Fällen sogar den
Speicherplatzoverhead.

Re: Wie leeren String aus Array ausfiltern?

am 13.04.2006 20:50:39 von Frank Seitz

Ingo Menger wrote:

> Mit der splice-Lösung machst Du aber in Wirklichkeit:
> - entferne die Elemente aus der Liste, die nicht die Eigenschaft E
> haben.
>
> Sie wird somit sofort untauglich, wenn es mir später einfällt, daß
> ich außerdem auch noch die Elemente der Ausgangsliste mit Eigenschaft
> E2 brauche. Denn dann sind alle Elemente, die Eigenschaft E2, aber
> nicht Eigenschaft E haben, gar nicht mehr da.

Ziemlich weit hergeholt. Es ging ja nicht darum, eine Ergebnismenge
zu bestimmen, sondern überflüssige Leerstrings aus einem Array
zu entfernen. Ich würde, wenn ich eine Struktur bereinigen will,
dies im Normalfall auf der Struktur selbst machen und nicht
eine Kopie dafür anfertigen. Aber klar, gibt es
auch andere Anwendungsfälle.

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

Re: Wie leeren String aus Array ausfiltern?

am 13.04.2006 21:08:43 von Slaven Rezic

Frank Seitz writes:

> Slaven Rezic wrote:
> > Frank Seitz writes:
> >>Frank Küster wrote:
> >>>
> >>>@oldarray = grep {! /pattern } @oldarray
> >>
> >>grep() hatte ich als erste Möglichkeit vorgeschlagen.
> >>Eine Lösung mit splice() halte ich im Gegensatz zu Dir
> >>für effizienter, da grep() ein neues Array aufbaut
> >>und Daten kopiert, während splice() nur wegwirft.
> >
> > Was in Perl effizient ist oder nicht, ist eigentlich nur durch
> > Benchmarks zu erfahren.
>
> Was die Ausführungszeit angeht, auf jeden Fall.
> Ich habe wohlweißlich gesagt, dass ich es für effizienter halte,
> nicht dass es effizienter ist.
> Effizienz schließt für mich übrigens Zeit *und* Platz ein.
>
> > Und oft gilt das Ergebnis nur für ein
> > (Betriebs-)System und eine Perl-Konfiguration und nur für bestimmte
> > Eingabedaten.
>
> Bei den allgemeinen Datenstrukturen und ihren Grundoperationen
> rechne ich nicht mit großartigen Variationen.

Interessant wird es, wenn Speicher angefordert werden muss. Dann ist
man von der malloc-Implementation des Systems abhängig. Zum Beispiel
stand eine Zeit lang im perl-hints-File für FreeBSD folgendet Text:

# In FreeBSD 4 and 5 the system malloc is performance-wise
# VERY bad for Perl-- we are talking of differences of not
# one, but TWO magnitudes.

Zwar wurde dieser Abschnitt später zurückgezogen (und usemymalloc=n
ist wieder Default), aber bei anderen Systemen finden sich ähnliche
Texte. Ich empfehle die Lektüre von perl/hints/*.sh :-)

>
> > Eine Lösung mit splice() hat den Vorteil, dass nicht mehr Speicher als
> > am Anfang verwendet wird, während bei grep() Speicherplatz für sowohl
> > Ergebnis- als auch Argumentliste gleichzeitig benötigt wird.
>
> Das war auch mein Hauptgedanke.
>
> > Bei splice() muss allerdings auch kopiert werden, da es sich bei
> > Perl-Arrays um echte Arrays und nicht um Listen handelt.
>
> Schon richtig. Aber das dürften ultraschnelle Verschiebeoperationen
> von zusammenhängendem Speicher sein, die maschinennah
> ausgeführt werden.
>
> > Die Lösung
> > mit grep() könnte bei der Anzahl der aufgerufenen Opcodes aber
> > effizienter sein.
>
> Gut möglich, dass das Iterieren auf Perl-Ebene in der
> slice()-Variante vergleichsweise teuer kommt.
>
> Wer probiert es mal aus?
>

Einen großen Unterschied dürfte auch die Größe der erzeugten Liste
sein: wenn die Ergebnisliste nur ein Element enthält, dann müsste bei
der grep-Lösung nur einmal kopiert werden, wohingegen bei einer
splice-Lösung unter Umständen n-1 Mal immer größere Speicherabschnitte
kopiert werden müssen.

Umgekehrt sieht es aus, wenn die Ergebnisliste alle n Elemente
enthält: dann muss bei grep n Mal kopiert werden, wohingegen bei der
splice-Lösung nichts gemacht werden muss.

Gruß,
Slaven

--
Slaven Rezic - slaven rezic de

tkrevdiff - graphical display of diffs between revisions (RCS, CVS or SVN)
http://ptktools.sourceforge.net/#tkrevdiff

Re: Wie leeren String aus Array ausfiltern?

am 13.04.2006 21:09:28 von David Haller

Frank Seitz wrote:
>> Die Lösung
>> mit grep() könnte bei der Anzahl der aufgerufenen Opcodes aber
>> effizienter sein.
>
> Gut möglich, dass das Iterieren auf Perl-Ebene in der
> slice()-Variante vergleichsweise teuer kommt.
>
> Wer probiert es mal aus?

==== t.pl ====
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);

my @testArray;
for my $size ( 1, 10, 100, 1000 ) {
@testArray = ('hallo','','bonjour','trulalla','','bye') x $size;
print "Arraysize: ", scalar @testArray, "\n";
cmpthese( 0,
{
'splicefea' => sub {
my $i = 0;
foreach ( @testArray ) {
if (/(^$)/) {
splice(@testArray, $i, 1);
}
$i++;
}
;
},
'splicere' => sub {
for (my $i = $#testArray; $i < $#testArray; $i++) {
if (/(^$)/) {
splice(@testArray, $i, 1);
}
}
;
},
'spliceeq' => sub {
for (my $i = $#testArray; $i < $#testArray; $i++) {
if ($_ eq "") {
splice(@testArray, $i, 1);
}
}
;
},
'splicelen' => sub {
for (my $i = $#testArray; $i < $#testArray; $i++) {
if (length $_ <= 0) {
splice(@testArray, $i, 1);
}
}
;
},
'grepre' => sub {
@testArray = grep( !/^$/, @testArray);
},
'grepstr' => sub {
@testArray = grep { !"" ; } @testArray;
},
'greplen' => sub {
@testArray = grep { length $_ > 0 } @testArray;
},
'shwhileeq' => sub {
@testArray = sort @testArray;
shift @testArray while( $testArray[0] eq "" );
},
'shwhilere' => sub {
@testArray = sort @testArray;
shift @testArray while( $testArray[0] =~ /^$/ );
},
'shwhilelen' => sub {
@testArray = sort @testArray;
shift @testArray while( length $testArray[0] <= 0);
},
});
}
====

$ perl t.pl ## Ausgabe gekuerzt
Arraysize: 6 Arraysize: 600
Rate Rate
grepre 32869/s grepre 398/s
greplen 37855/s greplen 456/s
grepstr 40698/s grepstr 509/s
splicefea 59566/s splicefea 1119/s
shwhilere 103070/s shwhilere 9281/s
shwhilelen 109278/s shwhileeq 9488/s
shwhileeq 112520/s shwhilelen 9488/s
splicere 139418/s splicere 141474/s
spliceeq 173036/s spliceeq 179375/s
splicelen 174978/s splicelen 181250/s
Arraysize: 60 Arraysize: 6000
Rate Rate
grepre 3974/s grepre 39.4/s
greplen 4387/s greplen 45.1/s
grepstr 5024/s grepstr 50.5/s
splicefea 10454/s splicefea 111/s
shwhilere 57101/s shwhilere 632/s
shwhileeq 60612/s shwhilelen 634/s
shwhilelen 61052/s shwhileeq 634/s
splicere 143357/s splicere 139636/s
spliceeq 173589/s splicelen 178645/s
splicelen 174973/s spliceeq 181250/s

Habe ich ne Variante vergessen? Dass die grep- (und die foreach-)
Varianten so lahm sind wundert mich etwas ...

Achso:
$ perl --version
This is perl, v5.8.6 built for i686-linux-thread-multi-64int-ld

HTH,
-dnh

--
Nicht alles, was hinkt, ist ein Vergleich.

Re: Wie leeren String aus Array ausfiltern?

am 13.04.2006 23:32:34 von Slaven Rezic

David Haller writes:

> Frank Seitz wrote:
> >> Die Lösung
> >> mit grep() könnte bei der Anzahl der aufgerufenen Opcodes aber
> >> effizienter sein.
> >
> > Gut möglich, dass das Iterieren auf Perl-Ebene in der
> > slice()-Variante vergleichsweise teuer kommt.
> >
> > Wer probiert es mal aus?
>
> ==== t.pl ====
> #!/usr/bin/perl
> use strict;
> use warnings;
> use Benchmark qw(cmpthese);
>
> my @testArray;
> for my $size ( 1, 10, 100, 1000 ) {
> @testArray = ('hallo','','bonjour','trulalla','','bye') x $size;
> print "Arraysize: ", scalar @testArray, "\n";
> cmpthese( 0,
> {
> 'splicefea' => sub {
> my $i = 0;
> foreach ( @testArray ) {
> if (/(^$)/) {
> splice(@testArray, $i, 1);
> }
> $i++;
> }

Moment! Hier ist @testArray reduziert. Und wird nie wieder auf den
Anfangswert zurückinitialisiert. Du musst bei jedem Durchlauf
@testArray neu setzen! Das gilt für alle Benchmarks.

Außerdem: /(...)/: Hier sind die Klammern unnötig und erzeugen jedesmal unnötigerweise ein $1.

Weiterhin bin ich mir nicht sicher, wie sich splice() innerhalb einer
foreach-Schleife verhält.

> ;
> },
> 'splicere' => sub {
> for (my $i = $#testArray; $i < $#testArray; $i++) {

Sollte das nicht eher

for (my $i = $#testArray; $i >= 0; $i--) {

sein? Ansonsten wird die for-Schleife genau einmal durchlaufen! (Ein
weiteres Argument für grep: man macht weniger Fehler!)

> if (/(^$)/) {

$_ existiert hier gar nicht!

> splice(@testArray, $i, 1);
> }
> }
> ;
> },
[...]
> 'grepre' => sub {
> @testArray = grep( !/^$/, @testArray);
> },
> 'grepstr' => sub {
> @testArray = grep { !"" ; } @testArray;

Das sieht falsch aus.

> },
> 'greplen' => sub {
> @testArray = grep { length $_ > 0 } @testArray;
> },

Ich vermisse eine grepeq-Variante.

[...]

Hier eine korrigierte abgespeckte Version:

#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);

for my $size (1000) {
my @_testArray = ('hallo','','bonjour','trulalla','','bye') x $size;
#my @_result = grep { $_ ne "" } @_testArray;
print "Arraysize: ", scalar @_testArray, "\n";
cmpthese( 0,
{
'spliceeq' => sub {
my @testArray = @_testArray;
for (my $i = $#testArray; $i >= 0; $i--) {
if ($testArray[$i] eq "") {
splice(@testArray, $i, 1);
}
}
#die if "@testArray" ne "@_result";
},
'grepeq' => sub {
my @testArray = @_testArray;
@testArray = grep { $_ ne "" } @testArray;
},
});
}

$ perl5.8.8 /tmp/t.pl
Arraysize: 6000
Rate spliceeq grepeq
spliceeq 26.7/s -- -20%
grepeq 33.2/s 24% --

$ perl5.8.8 -v
.... This is perl, v5.8.8 built for i386-freebsd ...

Gruß,
Slaven

--
Slaven Rezic - slaven rezic de

Lost in your Tk widget tree? Try
http://user.cs.tu-berlin.de/~eserte/src/perl/Tk-WidgetDump/

Re: Wie leeren String aus Array ausfiltern?

am 14.04.2006 09:15:09 von Frank Seitz

Slaven Rezic wrote:

> Hier eine korrigierte abgespeckte Version:
>
> #!/usr/bin/perl
> use strict;
> use warnings;
> use Benchmark qw(cmpthese);
>
> for my $size (1000) {
> my @_testArray = ('hallo','','bonjour','trulalla','','bye') x $size;
> #my @_result = grep { $_ ne "" } @_testArray;
> print "Arraysize: ", scalar @_testArray, "\n";
> cmpthese( 0,
> {
> 'spliceeq' => sub {
> my @testArray = @_testArray;
> for (my $i = $#testArray; $i >= 0; $i--) {
> if ($testArray[$i] eq "") {
> splice(@testArray, $i, 1);
> }
> }
> #die if "@testArray" ne "@_result";
> },
> 'grepeq' => sub {
> my @testArray = @_testArray;
> @testArray = grep { $_ ne "" } @testArray;
> },
> });
> }
>
> $ perl5.8.8 /tmp/t.pl
> Arraysize: 6000
> Rate spliceeq grepeq
> spliceeq 26.7/s -- -20%
> grepeq 33.2/s 24% --
>
> $ perl5.8.8 -v
> ... This is perl, v5.8.8 built for i386-freebsd ...

Also grep() ist schneller. Bei mir kommt raus:

Arraysize: 6000
Rate spliceeq grepeq
spliceeq 92.2/s -- -1%
grepeq 93.4/s 1% --

Bei mir liegen die beiden Varianten unter denselben
Testbedingungen also gleichauf. Interessant wurde es,
als ich die Arraygröße variiert habe

for my $size (qw(1 10 100 500 1000 1500)) {
...
print "\n";
}

Arraysize: 6
Rate grepeq spliceeq
grepeq 87959/s -- -31%
spliceeq 127326/s 45% --

Arraysize: 60
Rate grepeq spliceeq
grepeq 9815/s -- -34%
spliceeq 14941/s 52% --

Arraysize: 600
Rate grepeq spliceeq
grepeq 990/s -- -30%
spliceeq 1408/s 42% --

Arraysize: 3000
Rate grepeq spliceeq
grepeq 194/s -- -16%
spliceeq 230/s 18% --

Arraysize: 6000
Rate grepeq spliceeq
grepeq 91.9/s -- -1%
spliceeq 93.1/s 1% --

Arraysize: 9000
Rate spliceeq grepeq
spliceeq 47.3/s -- -19%
grepeq 58.6/s 24% --

Für kleinere Arraygrößen ist die Variante mit splice() schneller
(um etwa 50%). Dieser Vorteil schrumpft (bei mir) bis zu einer
Arraygröße von 6000 Elementen auf Null, dann überholt grep() und ist
ab da zunehmend im Vorteil (etwa 25% schneller bei 9000 Elementen).

Ändert man die Zahl der zu entfernenden Elemente
verschiebt sich das Bild in die eine oder andere Richtung.
Bei nur einem 1/6 statt 1/3 zu entfernenden Elementen
ergibt sich folgendes Bild:

Arraysize: 6
Rate grepeq spliceeq
grepeq 79816/s -- -40%
spliceeq 132000/s 65% --

Arraysize: 60
Rate grepeq spliceeq
grepeq 8773/s -- -44%
spliceeq 15806/s 80% --

Arraysize: 600
Rate grepeq spliceeq
grepeq 888/s -- -43%
spliceeq 1557/s 75% --

Arraysize: 3000
Rate grepeq spliceeq
grepeq 169/s -- -38%
spliceeq 272/s 61% --

Arraysize: 6000
Rate grepeq spliceeq
grepeq 83.3/s -- -25%
spliceeq 111/s 33% --

Arraysize: 9000
Rate grepeq spliceeq
grepeq 52.2/s -- -11%
spliceeq 58.7/s 12% --

Je weniger Elemente zu entfernen sind, desto stärker ist
der Anfangsvorteil der Variante mit splice(),
und andersrum: je mehr Elemente rausfallen, desto
eher ist die Variante mit grep() im Vorteil.
Das hatte Slaven schon vorhergesagt und leuchtet
auch unmittelbar ein.

Nicht betrachtet hierbei ist der Speicherbedarf, der
im Beispiel bei grep() während der Bearbeitung um etwa 2/3 bzw. 5/6
zunimmt, bei splice() sukzessive um 1/3 bzw. 1/6 schrupft.

Zusammenfassung:
Ich sehe mich, zumindest für übliche Arraygrößen, in meiner
Vermutung bestätigt, dass splice() besser ist.
Mit zunehmender Array-Größe wird die splice-Operation
jedoch immer teurer, so dass sie irgendwann teurer
ist als der Kopieraufwand, den grep() betreibt.
Hinzuzufügen ist noch: Dies alles ist eine eher
akademische Betrachtung. Für das normale Programm
spielt der Unterschied zwischen beiden Varianten
in der Praxis sicherlich keine Rolle, d.h. da ist es
Banane, wie man es programmiert.

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

Re: Wie leeren String aus Array ausfiltern?

am 14.04.2006 09:20:24 von Frank Seitz

David Haller wrote:
> Frank Seitz wrote:
>>
>>Gut möglich, dass das Iterieren auf Perl-Ebene in der
>>slice()-Variante vergleichsweise teuer kommt.
>>
>>Wer probiert es mal aus?

[Benchmark]

Danke für den Vergleich! (obwohl Du beachtliche Klopfer eingebaut
hattest, die hier natürlich nicht unentdeckt blieben ;)

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

Re: Wie leeren String aus Array ausfiltern?

am 14.04.2006 12:27:06 von hjp-usenet2

Frank Küster wrote:
> Frank Seitz wrote:
>> So ungefähr, nur dass Du erstens eine klassische for-Schleife
>> anstelle von foreach nehmen solltest. Grund:
>>
>> | "foreach" will get very confused if
>> | you add or remove elements within the loop body, for example with
>> | "splice". So don't do that.
>
> Ah, ich hatte genau aus diesem Grund ein ungutes Gefühl mit der
> Schleife, aber ich wusste überhaupt nicht, dass sich for und foreach
> unterschiedlich verhalten - ich dachte es seien einfach Synonyme.

Sind sie auch. Aber auch perldoc perlsyn unterscheidet zwischen "For
Loops" (Schleifen der Form »for[each] (EXPR; EXPR; EXPR) BLOCK«) und
"Foreach Loops" (Schleifen der Form »for[each] VAR (LIST) BLOCK«),
obwohl man bei beiden ganz nach Lust und Laune for oder foreach
schreiben kann.

hp

--
_ | Peter J. Holzer | Löschung von at.usenet.schmankerl?
|_|_) | Sysadmin WSR/LUGA |
| | | hjp@hjp.at | Diskussion derzeit in at.usenet.gruppen
__/ | http://www.hjp.at/ |

Re: Wie leeren String aus Array ausfiltern?

am 14.04.2006 17:56:59 von David Haller

Slaven Rezic wrote:
> David Haller writes:
>> Frank Seitz wrote:
>> >> Die Lösung
>> >> mit grep() könnte bei der Anzahl der aufgerufenen Opcodes aber
>> >> effizienter sein.
>> >
>> > Gut möglich, dass das Iterieren auf Perl-Ebene in der
>> > slice()-Variante vergleichsweise teuer kommt.
>> >
>> > Wer probiert es mal aus?
>>
>> ==== t.pl ====
>> #!/usr/bin/perl
>> use strict;
>> use warnings;
>> use Benchmark qw(cmpthese);
>>
>> my @testArray;
>> for my $size ( 1, 10, 100, 1000 ) {
>> @testArray = ('hallo','','bonjour','trulalla','','bye') x $size;
>> print "Arraysize: ", scalar @testArray, "\n";
>> cmpthese( 0,
>> {
>> 'splicefea' => sub {
>> my $i = 0;
>> foreach ( @testArray ) {
>> if (/(^$)/) {
>> splice(@testArray, $i, 1);
>> }
>> $i++;
>> }
>
> Moment! Hier ist @testArray reduziert. Und wird nie wieder auf den
> Anfangswert zurückinitialisiert. Du musst bei jedem Durchlauf
> @testArray neu setzen! Das gilt für alle Benchmarks.

*ARGS* *in die schaem-Ecke stell* Ich war wohl noch im Halbschlaf.

> Außerdem: /(...)/: Hier sind die Klammern unnötig und erzeugen jedesmal unnötigerweise ein $1.
>
> Weiterhin bin ich mir nicht sicher, wie sich splice() innerhalb einer
> foreach-Schleife verhält.

Da habe ich mit Absicht unbesehen Frank Küsters Version
genommen. Scheint aber zu funktionieren (getestet mit Ausgabe und
Stringvergleich).

[Weitere Peinlichkeiten gesnippt *AUA*]

> Ich vermisse eine grepeq-Variante.

s.u.

> [...]
>
> Hier eine korrigierte abgespeckte Version:

Uebernommen.

[..]
> $ perl5.8.8 /tmp/t.pl
> Arraysize: 6000
> Rate spliceeq grepeq
> spliceeq 26.7/s -- -20%
> grepeq 33.2/s 24% --
>
> $ perl5.8.8 -v
> ... This is perl, v5.8.8 built for i386-freebsd ...

$ perl SR.pl ### das ist deine Version
Arraysize: 6000
Rate spliceeq grepeq
spliceeq 22.4/s -- -16%
grepeq 26.7/s 19% --

Hier nochmal eine korrigierte Version von mir ... Ich hoffe diesmal
stimmt's (*seufz*) ...

====
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);
sub dprint {
print "$_[0]: »", join("« »", @{$_[1]}), "«\n";
}
my @testArray;
for my $size ( 1, 10, 100, 1000 ) {
@testArray = ('hallo','','bonjour','trulalla','','bye') x $size;
print "Arraysize: ", scalar @testArray, "\n";
my @result = grep { $_ ne "" } @testArray;
my @sortresult = sort grep { $_ ne "" } @testArray;
cmpthese( 0,
{
'splicefea' => sub {
my @A = @testArray; my $i = 0;
foreach ( @A ) {
if (/(^$)/) {
splice(@A, $i, 1);
}
$i++;
}; # dprint("splicefea", \@A);
# die if "@A" ne "@result";
},
'splicefeancap' => sub {
my @A = @testArray; my $i = 0;
foreach ( @A ) {
if (/^$/) {
splice(@A, $i, 1);
}
$i++;
}; # dprint("splicefeancap", \@A);
# die if "@A" ne "@result";
},
'splicere' => sub {
my @A = @testArray;
for (my $i = 0; $i <= $#A; $i++) {
if ($A[$i] =~ /^$/) {
splice(@A, $i, 1);
}
}; # dprint("splicere", \@A);
# die if "@A" ne "@result";
},
'spliceSR' => sub {
my @A = @testArray;
for (my $i = $#A; $i >= 0; $i--) {
if ($A[$i] eq "") {
splice(@A, $i, 1);
}
}; # dprint("spliceSR", \@A);
# die if "@A" ne "@result";
},
'spliceeq' => sub {
my @A = @testArray;
for (my $i = 0; $i <= $#A; $i++) {
if ($A[$i] eq "") {
splice(@A, $i, 1);
}
}; # dprint("spliceeq", \@A);
# die if "@A" ne "@result";
},
'splicelen' => sub {
my @A = @testArray;
for (my $i = 0; $i <= $#A; $i++) {
if (length $A[$i] <= 0) {
splice(@A, $i, 1);
}
}; # dprint("splicelen", \@A);
# die if "@A" ne "@result";
},
'grepre' => sub {
my @A = @testArray;
@A = grep( !/^$/, @A);
# dprint("grepre", \@A);
# die if "@A" ne "@result";
},
'grepne' => sub {
my @A = @testArray;
@A = grep { $_ ne "" ; } @A;
# dprint("grepne", \@A);
# die if "@A" ne "@result";
},
'greplen' => sub {
my @A = @testArray;
@A = grep { length $_ > 0 } @A;
# dprint("greplen", \@A);
# die if "@A" ne "@result";
},
'shwhileeq' => sub {
my @A = @testArray;
@A = sort @A;
shift @A while( $A[0] eq "" );
# dprint("shwhileeq", \@A);
# die if "@A" ne "@sortresult";
},
'shwhilere' => sub {
my @A = @testArray;
@A = sort @A;
shift @A while( $A[0] =~ /^$/ );
# dprint("shwhilere", \@A);
# die if "@A" ne "@sortresult";
},
'shwhilelen' => sub {
my @A = @testArray;
@A = sort @A;
shift @A while( length $A[0] <= 0);
# dprint("shwhilelen", \@A);
# die if "@A" ne "@sortresult";
},
});
}
====

Jetzt passen auch die Ergebnisse eher.

Arraysize: 6 Arraysize: 60 Arraysize: 600
Rate Rate Rate
splicere 20159/s grepre 2416/s splicere 243/s
grepre 20876/s splicere 2487/s grepre 244/s
greplen 23193/s greplen 2703/s greplen 274/s
grepne 23791/s grepne 2833/s grepne 287/s
splicefea 25606/s splicelen 3361/s splicelen 330/s
splicelen 26010/s spliceeq 3446/s spliceeq 337/s
spliceeq 26294/s splicefea 3469/s splicefea 342/s
spliceSR 26878/s spliceSR 3722/s shwhilere 359/s
shwhilere 27451/s shwhilere 3838/s spliceSR 370/s
splicefeancap 27922/s splicefeancap 3925/s splicefeancap 383/s
shwhilelen 30914/s shwhilelen 4174/s shwhilelen 389/s
shwhileeq 31513/s shwhileeq 4278/s shwhileeq 398/s

Arraysize: 6000 Arraysize: 30000
Rate Rate
splicere 18.7/s splicere 1.82/s
grepre 23.1/s spliceeq 2.03/s
splicelen 23.2/s splicelen 2.03/s
spliceeq 23.6/s splicefea 2.05/s
splicefea 23.9/s splicefeancap 2.12/s
greplen 25.7/s spliceSR 2.28/s
splicefeancap 26.0/s grepre 4.35/s
spliceSR 26.3/s shwhilere 4.67/s
grepne 26.7/s greplen 4.82/s
shwhilere 31.2/s shwhilelen 4.92/s
shwhilelen 33.2/s shwhileeq 4.99/s
shwhileeq 33.6/s grepne 5.03/s

Die 'shwhile*' sind natuerlich unbrauchbar, wenn die Reihenfolge im
Array erhalten bleiben soll.

Interessant, dass wenn die Laufzeit interessant wird, das grep im
Vergleich immer besser abschneidet ...

-dnh

--
This is sick. Count me in. -- Arvid G.

Re: Wie leeren String aus Array ausfiltern?

am 14.04.2006 19:09:19 von Frank Seitz

David Haller wrote:

> Hier nochmal eine korrigierte Version von mir ... Ich hoffe diesmal
> stimmt's (*seufz*) ...

Leider nein: Die for-Schleifen sind immer noch nicht korrekt,
da nach einem splice() ein Element übergangen wird.
Außerdem sind sie ungünstig programmiert, da sie vom Anfang
zum Ende laufen. Andersrum ist es besser.

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

Re: Wie leeren String aus Array ausfiltern?

am 14.04.2006 23:23:17 von David Haller

Frank Seitz wrote:
> David Haller wrote:
>
>> Hier nochmal eine korrigierte Version von mir ... Ich hoffe diesmal
>> stimmt's (*seufz*) ...
>
> Leider nein: Die for-Schleifen sind immer noch nicht korrekt,
> da nach einem splice() ein Element übergangen wird.
> Außerdem sind sie ungünstig programmiert, da sie vom Anfang
> zum Ende laufen. Andersrum ist es besser.

Stimmt, man sollte die Testdaten etwas "fieser" gestalten...

@testArray = ('hallo','', '', 'bonjour','trulalla','','bye', '') x $size;

Da merkt man's dann. Mit 'for (my $i = $#A; $i >= 0; $i--) {' geht's
und die foreach sind beide falsch. Und wenn man schon dabei ist, kann
man auch gleich noch "undef" in der Eingabe erlauben und diese
ebenfalls rauswerfen.

Jetzt aber (wenn immer noch Fleher drin sind geb' ich auf):

==== etwas platzsparender umbrochen und dprint/die if weggelassen ====
#!/usr/bin/perl
use strict; use warnings; use Benchmark qw(cmpthese);

my @testArray;
for my $size ( 1, 10000 ) {
@testArray = ('', 'hallo', '', '', 'bonjour', undef,
undef, '', 'trulalla', 'bye', '', '') x $size;
print "Arraysize: ", scalar @testArray, "\n";
cmpthese( $size >= 3000 ? 10 : 0,
{
'splicere' => sub { my @A = @testArray;
for (my $i = $#A; $i >= 0; $i--) {
if (! defined $A[$i] || $A[$i] =~ /^$/) {
splice(@A, $i, 1); } };
},
'spliceeq' => sub { my @A = @testArray;
for (my $i = $#A; $i >= 0; $i--) {
if (! defined $A[$i] || $A[$i] eq "") {
splice(@A, $i, 1); } };
},
'splicelen' => sub { my @A = @testArray;
for (my $i = $#A; $i >= 0; $i--) {
if ( ! defined $A[$i] || length $A[$i] <= 0) {
splice(@A, $i, 1); } };
},
'grepre' => sub { my @A = @testArray;
@A = grep( defined $_ && !/^$/, @A);
},
'grepne' => sub { my @A = @testArray;
@A = grep { defined $_ && $_ ne "" ; } @A;
},
'greplen' => sub { my @A = @testArray;
@A = grep { defined $_ && length $_ > 0 } @A;
},
'shwhileeq' => sub { my @A = @testArray;
{ no warnings qw(uninitialized); @A = sort @A; }
shift @A while( ! defined $A[0] || $A[0] eq "" );
},
'shwhilere' => sub { my @A = @testArray;
{ no warnings qw(uninitialized); @A = sort @A; }
shift @A while( ! defined $A[0] || $A[0] =~ /^$/ );
},
'shwhilelen' => sub { my @A = @testArray;
{ no warnings qw(uninitialized); @A = sort @A; }
shift @A while( ! defined $A[0] || length $A[0] <= 0);
},
});
}
1;
====

$ ./t.pl
Arraysize: 12 Arraysize: 120000
Rate splicere s/iter splicere
splicere 8643/s -- splicere 9.83 --
splicelen 12009/s 39% splicelen 9.51 3%
shwhilere 12200/s 41% spliceeq 9.20 7%
spliceeq 12277/s 42% shwhilere 1.20 723%
grepre 13048/s 51% shwhilelen 1.14 766%
shwhilelen 13915/s 61% shwhileeq 0.986 897%
shwhileeq 14095/s 63% grepre 0.779 1162%
greplen 14872/s 72% greplen 0.695 1315%
grepne 15215/s 76% grepne 0.667 1374%

Das ist dann doch recht eindeutig... Man merkt, dass perl auf Laufzeit
zuungunsten Speicherverbrauch "optimiert", wobei es wohl immer auch
Alternativen gibt, um den Speicherverbrauch zuungunsten der Laufzeit
zu optimieren (eben z.B. splice vs. grep)...

-dnh

--
/ "Camels and llamas and hashes and scalars / Cute little modules talking \
[ to mailers / Regexes munging my humungous strings / These are a few of my ]
\ favourite things" -- Malcolm Ray, on making Perl sing /

Re: Wie leeren String aus Array ausfiltern?

am 15.04.2006 12:27:57 von hjp-usenet2

David Haller wrote:
[ neue Testdaten mit mehr Leerstrings und auch im Code ein bisschen was
geändert ]
> $ ./t.pl
> Arraysize: 12 Arraysize: 120000
> Rate splicere s/iter splicere
> splicere 8643/s -- splicere 9.83 --
[...]
> grepne 15215/s 76% grepne 0.667 1374%
>
> Das ist dann doch recht eindeutig... Man merkt, dass perl auf Laufzeit
> zuungunsten Speicherverbrauch "optimiert", wobei es wohl immer auch
> Alternativen gibt, um den Speicherverbrauch zuungunsten der Laufzeit
> zu optimieren (eben z.B. splice vs. grep)...

Wo optimiert da *perl*? Du als Programmierer hast hier die Möglichkeit,
in die eine oder andere Richtung zu optimieren, Perl optimiert da gar
nichts. "Kopiere alle Elemente, die eine bestimmte Bedingung erfüllen"
und "Lösche alle Elemente, die diese Bedingung nicht erfüllen" sind zwei
vollkommen unterschiedliche Operationen, die beide zum gewünschten
Ergebnis führen *können*, aber nicht *müssen*. Das hängt halt vom
gewünschten Ergebnis ab. Dass diese Operationen unterschiedliche
Laufzeiten haben, ist auch klar, daraus irgendwelche Schlüsse zu ziehen,
in welche Richtung Perl "optimiert", ist reichlich gewagt.

Eher ist - wenn man nur die splice-Operation hernimmt - der umgekehrte
Schluss zulässig: Perl könnte Arrays auch als verkettete Listen
darstellen: Dann wäre das Löschen eines Elements aus einer großen Liste
schneller, aber der Speicherverbrauch höher. Somit optimiert Perl den
Speicherverbrauch zuungunsten der Laufzeit.

Das ist aber natürlich auch Unsinn. Eine Darstellung als verkettete
Liste hätte deutlich höhere Zugriffszeiten auf einzelne Elemente zur
Folge. Der Schluss, dass Perl (also eigentlich Larry) zugunsten häufiger
Operationen (Zugriff auf Array-Elemente) und zuungunsten seltener
Operationen (splice) optimiert, liegt daher nahe.

hp

--
_ | Peter J. Holzer | Löschung von at.usenet.schmankerl?
|_|_) | Sysadmin WSR/LUGA |
| | | hjp@hjp.at | Diskussion derzeit in at.usenet.gruppen
__/ | http://www.hjp.at/ |