Schrift
[thread]8023[/thread]

Array "zusammenziehen" (undef Stellen löschen)



<< |< 1 2 >| >> 12 Einträge, 2 Seiten
fulug
 2006-05-28 03:51
#66641 #66641
User since
2005-12-07
9 Artikel
BenutzerIn
[default_avatar]
hallo,
Ich wollte ein Programm schreiben, das (siehe Threadtitel) die undefinierten Stellen eines Arrays löschen sollte.
Mein Buch sagt:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/perl

@old = ( 2, 5, 13, undef, 6, 8, undef, 3);

@new = ();

for ($i=0;$i<=$#old;$i++)
{
$new[$n++] = $old[$i] if defined $old[$i]; }

print "\n@old";
print "\n\n@new\n\n";


Das heisst doch, dieses Skript löscht nicht die undefinierten Stellen, sondern schreibt die definierten in ein anderes Array!?
Ich dachte da eher an eine Lösung mit "splice".
Also in etwa so:

Code: (dl )
1
2
3
4
5
6
7
8
 
$i=0;
foreach (@old)
{ if ($old[$i] != defined)
{ splice @old,$old[$i],1; }
$i++;

}

Allerdings hat diese Methode (auch in etlichen Variationen) kein brauchbares Ergebnis hervorgebracht.
Könnte mich jemand aufklären?

mfg fulug
betterworld
 2006-05-28 05:45
#66642 #66642
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
Manchmal mag Perl es nicht, wenn man Arrays manipuliert, waehrend man ueber sie manipuliert. Du solltest den Algorithmus also vielleicht in zwei Schleifen aufteilen.

Das war jetzt aber nur geraten. Ich habe das Script nicht naeher analysiert und weiß nicht, warum genau es "kein brauchbares Ergebnis" liefert. Du solltest dies naeher beschreiben, denn es ist keine genaue Phrase.
Ronnie
 2006-05-28 10:28
#66643 #66643
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
In Perl hast du hierfür viele Möglichkeiten. Wenn du splice nutzen willst, musst du von hinten über das Array wandern, da beim splicen ja dein Array kürzer wird und so deine Indices nicht mehr stimmen. Die Variante mit grep ist wahrscheinlich die, die erfahrenere Perlprogrammierer wohl intuitiv wählen würden.
Code: (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
#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

my @old = ( 2, 5, 13, undef, 6, 8, undef, 3);

# mit splice (rückwärts durch das Array)

for (reverse 0..$#old) {
warn "splicing: \@old[$_]" and splice @old, $_, 1 unless defined $old[$_];
}

print Dumper \@old;

# ohne Zählvariable

@old = ( 2, 5, 13, undef, 6, 8, undef, 3);
my @new = ();

for (@old) { push @new, $_ if defined $_ };
@old = @new;

print Dumper \@old;

# die perl-typische Variante

@old = ( 2, 5, 13, undef, 6, 8, undef, 3);
@old = grep { defined } @old;
print Dumper \@old;
pq
 2006-05-28 13:45
#66644 #66644
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
erwartest du viele undefs, ist splice zu langsam.
ein
@array = grep defined, @array;
sollte es tun und ist, denke ich, auch gut verständlich. und kurz =)
ansonsten, wenn du nicht viele undefs erwartest, einfach, wie ronnie es
gezeigt hat, rückwärts iterieren.
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
nepos
 2006-05-28 16:15
#66645 #66645
User since
2005-08-17
1420 Artikel
BenutzerIn
[Homepage] [default_avatar]
Kann man sowas ned auch mit map machen?
pq
 2006-05-28 16:43
#66646 #66646
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
[quote=nepos,28.05.2006, 14:15]Kann man sowas ned auch mit map machen?[/quote]
sicher:
@array = map { defined $_ ? $_ : () } @array;

aber die frage ist, was genau hast du gegen das besser lesbare
@array = grep defined, @array;
?
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
nepos
 2006-05-28 19:11
#66647 #66647
User since
2005-08-17
1420 Artikel
BenutzerIn
[Homepage] [default_avatar]
Nix, das mit grep is ok :)
Nur das mit den Schleifen waer mir zu umstaendlich.
betterworld
 2006-05-28 19:14
#66648 #66648
User since
2003-08-21
2613 Artikel
ModeratorIn

user image
Stimmt, auf das mit grep haette ich auch kommen sollen. Der Nachteil ist allerdings, dass ein neues Array zusammengebaut wird, was bei sehr großen Arrays speicherintensiv sein kann.
fulug
 2006-05-29 12:31
#66649 #66649
User since
2005-12-07
9 Artikel
BenutzerIn
[default_avatar]
Also dankeschön für die vielen Antworten.
Ich vermute, dass das mit den Indizes gestimmt hat (danke @Ronnie) , da das neue Array (also das ge"splice"te) scheinbar willkürliche Lücken enthielt.
Nach dem, was ich jetzt erfahren habe, sind sie aber doch nicht soo willkürlich ;-)
Danke.

fulug\n\n

<!--EDIT|fulug|1148891550-->
esskar
 2006-05-29 16:27
#66650 #66650
User since
2003-08-04
7321 Artikel
ModeratorIn

user image
ansonsten - in der schleifen variante - würde ich statt
Code: (dl )
$new[$n++] = ...;

eher
Code: (dl )
push @new, ...;

wählen;

ich würde ein array aber auch nicht @new nennen :)\n\n

<!--EDIT|esskar|1148906837-->
<< |< 1 2 >| >> 12 Einträge, 2 Seiten



View all threads created 2006-05-28 03:51.