Re: How to connect more arrays to a new array
by BrowserUk (Patriarch) on Apr 28, 2003 at 02:08 UTC
|
my @new = do{local %h; ++@h{@a,@b,@c,@d}; keys %h;};
Examine what is said, not who speaks.
1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
3) Any sufficiently advanced technology is indistinguishable from magic.
Arthur C. Clarke.
| [reply] [d/l] |
|
my @new = keys %{{ map +($_ => undef), @a, @b, @c, @d }};
It should be noted that the difference to the grep solution is that this won't preserve any kind of order.
Makeshifts last the longest. | [reply] [d/l] |
|
@a=1.10; @b=1..100; @c=1..1000; @d=1..10000;
use Benchmark 'cmpthese';
$ari = '@A = keys %{{ map +($_ => undef), @a, @b, @c, @d }};';
$buk = '@B = do{local %h; ++@h{@a,@b,@c,@d}; keys %h};';
cmpthese( -1, { ari=>$ari, buk=>$buk });
(warning: too few iterations for a reliable count)
(warning: too few iterations for a reliable count)
Rate ari buk
ari 1.69/s -- -28%
buk 2.36/s 39% --
cmpthese( -3, { ari=>$ari, buk=>$buk });
Rate ari buk
ari 1.81/s -- -22%
buk 2.32/s 28% --
cmpthese( -3, { ari=>$ari, buk=>$buk });
Rate ari buk
ari 1.82/s -- -24%
buk 2.40/s 32% --
print 'Same' if "@A" eq "@B"
Same
Examine what is said, not who speaks.
1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
3) Any sufficiently advanced technology is indistinguishable from magic.
Arthur C. Clarke.
| [reply] [d/l] |
|
|
|
|
wow. that's amazing. ++ for you.
| [reply] |
|
++@h{@a,@b,@c,@d};
I tried this to peer into the hash:
while ( my ($k, $v) = each %h ) {
print "$k:$v.\n";
}
And I just got a bunch of uninitialized value warnings. How does that statement work, and what does it do? | [reply] [d/l] [select] |
|
The @h{@a,@b,@c,@d} syntax is a hash slice and it returns a list of all values in %hash that corresponds to keys represented by the array elements. It will auto-vivify elements that do not exist (hence your "uninitiliazed value" warnings). The preincrement operator is apparently taking the final element of the list and incrementing it. In other words, this is an obfuscated way of incrementing a single hash value, but with the side effect of auto-vivifying others. The following code snippet demonstrates:
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Indent = 1;
my %hash = (
foo => 1,
bar => 2,
baz => 3,
quux => 4
);
my @a = qw(foo bar asdf);
my @b = qw(baz);
++@hash{@a,@b};
print Dumper \%hash;
That auto-vivifies $h{asdf} and increments $h{baz} to 4.
Cheers,
Ovid
New address of my CGI Course.
Silence is Evil (feel free to copy and distribute widely - note copyright text) | [reply] [d/l] |
|
|
$hash{"key"}
does - give you access to the value stored in the hash under that key. In the same way, you can say
@hash{"key1", "key2"}
which gives you access to an entire list of values, indexed by the given keys. This is called a slice (and exists, in analogous form, for arrays too). Now, when you assign to that list, regardless of how many values you provide, all of the keys in the list pop into existence as entries in the hash. If there are not enough values given, any extraneous keys are assigned the undefined value. So
++@h{@a,@b,@c,@d};
leads to all of the values stored in @a etc being forced to become keys of the hash %h. And because hash keys cannot be duplicated, the list of keys for the resulting hash contains only one instance of each unique element from the arrays used as keys. I personally strongly prefer to write it as
@h{@a,@b,@c,@d} = ();
For all intents and purposes the effect is the same, it just doesn't look nearly as confusing as the ++ operator on the other one.
Makeshifts last the longest. | [reply] [d/l] [select] |
|
I was part way through a long-winded explaination when the latest episode of Enterprise came on. In the meantime the other respondants have explained it much better than I was.
The only addition I would make is that the ++ serves only one purpose, that of inhibiting the "Useless use of hash slice in void context" warning message that results were it not there. I agree with Aristotle that assigning an empty list is a much clearer way of acheiving this, and is the way I will do this in future.
An added bonus is that for anything other than the smallest datasets, it is slightly more efficient.
Examine what is said, not who speaks.
1) When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.
2) The only way of discovering the limits of the possible is to venture a little way past them into the impossible
3) Any sufficiently advanced technology is indistinguishable from magic.
Arthur C. Clarke.
| [reply] |
|
@x{@y} = @z; means the same thing as:
foreach my $i (0 .. $#y)
{
$x{$y[$i]} = $z[$i];
}
By extension, ++@x{@y}; means (roughly) the same thing as:
for my $i (0 .. $#y)
{
$i == 0 ? $x{$y[$i]} = 1 : $x{$y[$i]} = undef;
}
Does that make sense now?
------ We are the carpenters and bricklayers of the Information Age. Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement. Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified. | [reply] [d/l] [select] |
Re: How to connect more arrays to a new array
by samurai (Monk) on Apr 28, 2003 at 02:22 UTC
|
Hashes are the best data structures to use when trying to create arrays with unique values, because the keys are guaranteed to be unique (duplicate keys are overwritten as opposed to being appended to the stack). When you start using hashes to do lookups for uniqueness, you've learned a valuable skill. Here's some commented code for how to do this:
# your arrays
my @a = qw(a c d);
my @b = qw(s d v);
my @c = qw(l d s);
my @d = qw(i c f);
# the hash we'll use to preserve uniqueness
my %unique = ();
# for every character in each of the defined arrays
for my $char (@a, @b, @c, @d) {
# whenever we run into a character, we set its
# corresponding value to 1 in the unique hash. Even if we
# run into the same character more than once, it'll only have
# a single entry in our hash, as is the nature of hashes.
$unique{$char} = 1;
}
# now, the keys in the %unique hash should be the unique
# values from those arrays. We'll sort the keys for good
# measure
my @unique = sort keys %unique;
# @unique is now the unique elements of those arrays. Kudos.
Hashes are your friend (I use them a LOT when looking for duplicates in company data files). Learn to use them wisely and you'll appreciate perl's power and simplicity a lot sooner.
Or, for a quickie:
my %unique = map { $_=>1 } @a, @b, @c, @d;
my @unique = sort keys %unique;
--
perl: code of the samurai | [reply] [d/l] [select] |
Re: How to connect more arrays to a new array
by Aristotle (Chancellor) on Apr 28, 2003 at 01:50 UTC
|
my @new = do{
my %seen;
grep !$seen{$_}++, @a, @b, @c, @d;
};
Makeshifts last the longest. | [reply] [d/l] |
|
Ah, the solution from the FAQ. Unfortunally, the FAQ is wrong.
Here's one array where the FAQ solution will give the wrong
answer:
@a = (undef, "");
Ooops. The FAQ assumes the values map to unique strings. But
that isn't true, the undefined value maps to an empty string.
And then I haven't shown examples with references, tied variables
or objects with overloaded stringification that all can cause
the FAQ solution to give the wrong results.
Abigail | [reply] [d/l] |
|
The problem is how to define equity once you start slinging around tied or overloaded objects. By equal value, by equal reference, or by entirely different semantics? It's a question with very individual replies depending on the situation, and there can't be a universal solution. As for the undef, which is actually a common case, you are right, I had forgotten about that, even though I've fixed it before.
my @new = do{
my (%seen, $seen_undef);
grep defined ? !$seen{$_}++ : !$seen_undef++, @a, @b, @c, @d;
};
Makeshifts last the longest. | [reply] [d/l] |
|
my @new = do{local %h; @h{@a,@b,@c,@d} = (@a,@b,@c,@d); values %h};
Adapted from BrowserUk's code
--
integral, resident of freenode's #perl
| [reply] [d/l] |
|
Re: How to connect more arrays to a new array
by The Mad Hatter (Priest) on Apr 28, 2003 at 01:47 UTC
|
This sure sounds like homework to me... You could stuff the arrays into a hash with the elements as keys (to ensure uniqueness) though, but I'm sure there is a better, more efficient solution. | [reply] |
Re: Find unique elements from multiple arrays
by slim (Novice) on Apr 28, 2003 at 14:28 UTC
|
@a = qw (a c d);
@b = qw(s d v);
@c = qw(l d s);
@d = qw(i c f);
@new = (@a,@b,@c,@d);
@new{@new} = ();
@new = keys %new;
| [reply] [d/l] |
Re: Find unique elements from multiple arrays
by Kjetil (Sexton) on Apr 30, 2003 at 12:13 UTC
|
Have you checked out Array::Unique? Works very well for my purposes, is really cool, I think.... :-)
You can tie an array, and it only allows unique values to be added. | [reply] |