Re: check if an element exists in array
by GrandFather (Saint) on Apr 19, 2008 at 08:56 UTC
|
For focused advice you need to give us the bigger picture. If the search is occasional or the array is small (supply your own definition for both those) then grep is the tool of choice. If you don't care about the original order of the data and the data set is of modest size (again supply your own definition) then a hash of arrays may be appropriate. If the data size is modest (ditto) but you need order information add an ordinal along with the data value for each item (see below). If the data is large, use a database.
For the penultimate option consider:
use strict;
use warnings;
my $entries = 0;
my %data;
while (<DATA>) {
chomp;
my ($name, $value) = split ' ', $_, 2;
push @{$data{$name}}, [$entries++, $value];
}
for my $name (sort keys %data) {
print "$name\n";
print " $_->[1]\n" for sort {$a->[0] <=> $b->[0]} @{$data{$name}
+};
}
__DATA__
Jim 12
John 15
Peter 08
Andrew 34
Jim 57
Andreas 27
Prints:
Andreas
27
Andrew
34
Jim
12
57
John
15
Peter
08
Perl is environmentally friendly - it saves trees
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: check if an element exists in array
by FunkyMonk (Chancellor) on Apr 19, 2008 at 08:38 UTC
|
If all you want to do is check if the name is in the list then a hash is the way to go. But, to search an AoA, you could use grep:
my @names = (
[ qw/Jim 12/ ],
[ qw/John 15/ ],
[ qw/Peter 08/ ],
[ qw/Andrew 34/ ],
[ qw/Jim 57/ ],
[ qw/Andreas 27/ ],
);
my $name = 'Jim';
#simple searching
if ( grep { $_->[0] eq $name } @names ) {
print "$name\'s in the list\n";
}
# or to get all of $name's entries
for ( grep { $_->[0] eq $name } @names ) {
print "@$_\n";
}
Output:
Jim's in the list
Jim 12
Jim 57
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
I wanted to use a hash, but how will I build it? I do not have unique names...
| [reply] [Watch: Dir/Any] |
|
Using @names as before...
my %names_h = map { $_->[0] => 1 } @names;
# map { @$_ } @names; # similar, but more scary
my $name = 'Jim';
print "Jim's in the hash\n"
if $names_h{$name};
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
Re: check if an element exists in array
by moritz (Cardinal) on Apr 19, 2008 at 08:36 UTC
|
You can build a hash, but perhaps you need to store arrays as the hash values, not the strings directly.
Or you can build an array and a hash, and preserve multiple names only in the array.
Or of course you can just iterate over the array to find the names, but that's very inefficient, especially if you do it repeatedly. | [reply] [Watch: Dir/Any] |
Re: check if an element exists in array
by Not_a_Number (Prior) on Apr 19, 2008 at 11:55 UTC
|
As you can no doubt deduce from the replies that you have received so far, your requirements remain vague. The question implied by your title, "check if an element exists in array", has been more than adequately dealt with. But from your later comments, this is not what you really want.
Please correct me if I'm wrong, but it seems to me that your real requirements are as follows:
- You have a file, in the format indicated in your OP.
- You get input from somewhere, consisting of a name.
- If the name exists in the first column of the file, you want to output it, followed by the corresponding number in the second column.
What is not clear, however, is what output you want if the name occurs more than once in the file, ie for input of 'Jim' in your example, I see several possibilities:
Jim 12 # Use first occurrence
Jim 57 # Use last occurrence
Jim 12, 57 # List of all numbers associated with Jim
Jim 69 # Jim's total 'score'
Sorry, name 'Jim' occurs more than once # Or some similar warning
Based on the answers provided above, you should be able to code for any of these. What I suggest is that you now write some code, and come back to us if you still can't get it to do what you want. But please, in that case, tell us what it is that you want! | [reply] [Watch: Dir/Any] [d/l] |
Re: check if an element exists in array
by mscharrer (Hermit) on Apr 19, 2008 at 09:23 UTC
|
Is the order of the lines meaningfull?
If not you could use a hash which holds an array with all the values:
my %people;
while( my $line = <IN> ) {
my ($name, $value) = split /\s+/, $line;
if (!exists $people{$name}) {
$people{$name} = [ $value ]; # store array with one value
}
else {
push @{$people{$name}}, $value; # push 2nd,3rd,.. value on arr
+ay
}
}
The %people hash would then look like:
%people = (
'Andreas' => [
'27'
],
'John' => [
'15'
],
'Andrew' => [
'34'
],
'Jim' => [
'12',
'57'
],
'Peter' => [
'08'
]
);
This preserves the order of the values but not the order of the names. | [reply] [Watch: Dir/Any] [d/l] [select] |
|
You can save yourself some typing as Perl will auto-vivify the anonymous array for you if it doesn't exist already. Your
if (!exists $people{$name}) {
$people{$name} = [ $value ]; # store array with one value
}
else {
push @{$people{$name}}, $value; # push 2nd,3rd,.. value on arr
+ay
}
can become
push @{$people{$name}}, $value;
I hope this is of interest. Cheers, JohnGG | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: check if an element exists in array
by jethro (Monsignor) on Apr 19, 2008 at 11:06 UTC
|
if (!exists $people{$name}) {
$people{$name} = $value; # store array with one value
}
else {
$people{$name} .= ",$value"; # push 2nd,3rd,.. value on array
You can just print the string stored in the hash or get at the numbers with my @numbers= split /,/,$value
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: check if an element exists in array
by elmex (Friar) on Apr 19, 2008 at 09:08 UTC
|
If the task at hand is just to check whether the name is in the file the best would probably to analyze the contents
of the file directly:
my $name = 'Jim';
my $name_len = length $name;
while (<STDIN>) {
if (substr ($_, 0, $name_len) eq $name) {
print "Jim exists!\n";
last;
}
}
Of course I doubt that this is the only thing you want to do with that data, but the less processing of the data you do, and the easier the solution, the faster it usually is :)
But note that my code is just a concept code. If someone named 'Jimbo' would be in that file it would also match.
The correct solution depends on which delimiter you use to
seperate the name form the numbers.
As said in above comments: There is the rule that for low
n O(n) is equal to O(1) :-)
So a grep is usually fine for n =~ 100.
| [reply] [Watch: Dir/Any] [d/l] |
Re: check if an element exists in array
by Tux (Canon) on Apr 14, 2011 at 06:21 UTC
|
use List::Util qw(first);
first { $_ eq $needle } @list and say "Found!";
Enjoy, Have FUN! H.Merijn
| [reply] [Watch: Dir/Any] [d/l] |
Re: check if an element exists in array
by RecursionBane (Beadle) on Apr 12, 2011 at 01:43 UTC
|
For those getting here through the Google terms "element exists in array perl", here's a simple routine I wrote because I wanted something similar to TCL's "lsearch -exact" but with a binary return:
# Checks if a provided element exists in the provided list
# Usage: isInList <needle element> <haystack list>
# Returns: 0/1
sub isInList {
my $needle = shift;
my @haystack = @_;
foreach $hay (@haystack) {
if ( $needle eq $hay ) {
return 1;
}
}
return 0;
}
Of course, this should only be used on small haystacks (a few hundred elements at most).
| [reply] [Watch: Dir/Any] [d/l] |
|
sub isInList {
my( $d, $it ) = ( "\0", @_ );
join( $d, '', @_, '' ) =~ /$d\Q$it\E$d/
}
Caveat: This treats all the values as strings. Input values which are not strings will get stringified! This may or may not yield the desired results.
| [reply] [Watch: Dir/Any] [d/l] |
|
Elegant! Does Perl automagically return the last modified variable when returning from a subroutine?
| [reply] [Watch: Dir/Any] |
|