%hash = map { $_ => 1 } @array;
Это не столь коротко как "@hash {@array} =..." решения, но те требуют, чтобы хеш и массив уже были определены где-то в другом месте, тогда как этот может взять анонимный массив и возвратить анонимный хеш.
То, что это делает, является взятием каждый элемент в массиве, и разделите на пары его с "1". Когда этот список (ключ, 1, ключ, 1, ключевой 1) пары присвоены хешу, нечетные становятся ключами хеша, и четные становятся соответствующими значениями.
Вы могли бы также хотеть проверить Связь:: IxHash, который реализует заказанные ассоциативные массивы. Это позволило бы Вам делать оба типа поисков (хеш и индекс) на одной копии Ваших данных.
Если Вы делаете много набора теоретические операции - можно также использовать Набор:: Скаляр или подобный модуль. Тогда $s = Set::Scalar->new( @array )
создаст Набор для Вас - и можно запросить его с: $s->contains($m)
.
Вы могли также использовать Perl6:: Соединение .
use Perl6::Junction qw'any';
my @arr = ( 1, 2, 3 );
if( any(@arr) == 1 ){ ... }
Я всегда думал, что
foreach my $item (@array) { $hash{$item} = 1 }
было, по крайней мере, хорошо и читаемый / удобный в сопровождении.
Обратите внимание, что при вводе if ( exists $hash{ key } )
isn’t слишком много работы для Вас (начиная с которого я предпочитаю использовать, вопрос, представляющий интерес является действительно присутствием ключа, а не правдоподобием его значения), тогда можно использовать короткое и сладкое
@hash{@key} = ();
@hash{@keys} = undef;
синтаксис здесь, где Вы обращаетесь к хешу с @
, является частью хеша. Мы в основном говорим $hash{$keys[0]}
И $hash{$keys[1]}
, И $hash{$keys[2]}
... список на левой стороне =, lvalue, и мы присваиваем тому списку, который на самом деле входит в хеш и устанавливает значения для всех именованных ключей. В этом случае я только определил одно значение, так, чтобы значение вошло $hash{$keys[0]}
, и другие записи хеша, которые все автооживляют (оживают) с неопределенными значениями. [Мое исходное предложение здесь было установлено выражение = 1, который установит тот один ключ к 1 и другие к undef
. Я изменил его для непротиворечивости, но как мы будем видеть ниже, точные значения не имеют значения.]
, Когда Вы понимаете, что lvalue, выражение на левой стороне =, является списком, созданным из хеша, тогда это начнет иметь некоторый смысл, почему мы используем это @
. [Кроме я думаю, что это изменится в Perl 6.]
идея здесь состоит в том, что Вы используете хеш в качестве набора. То, что имеет значение, не является значением, которое я присваиваю; это - просто существование ключей. Таким образом, то, что Вы хотите сделать, не является чем-то как:
if ($hash{$key} == 1) # then key is in the hash
вместо этого:
if (exists $hash{$key}) # then key is in the set
на самом деле более эффективно просто работать exists
проверка, чем обеспокоиться значением в хеше, хотя мне важной вещью здесь является просто понятие, что Вы представляете набор только с ключами хеша. Кроме того, кто-то указал, что при помощи [1 111] как значение здесь, мы используем меньше пространства памяти, чем мы были бы, присваивая значение. (И также генерируйте меньше беспорядка, поскольку значение не имеет значения, и мое решение присвоило бы значение только первому элементу в хеше и оставило бы другие undef
, и некоторые другие решения поворачивают колеса телеги для создания массива значений для входа в хеш; полностью потраченное впустую усилие).
@hash{@array} = (1) x @array;
Это - часть хеша, список значений от хеша, таким образом, это получает список-y впереди.
От документы :
, Если Вы смущены тем, почему Вы используете там на части хеша вместо '% ', думают он как это. Тип скобки (квадратный или изогнутый) управляет, является ли это массивом или хешем, посмотревшим на. С другой стороны, начальный символ (' $' или) на массиве или хеше указывает, возвращаете ли Вы сингулярное число (скаляр) или множественный (список).
Решение Raldi может быть сжато до этого ('=>' из оригинала, не необходимо):
my %hash = map { $_,1 } @array;
Эта техника может также использоваться для того, чтобы превратить текстовые списки в хеши:
my %hash = map { $_,1 } split(",",$line)
Дополнительно, если у Вас есть строка значений как это: "foo=1, bar=2, baz=3" можно сделать это:
my %hash = map { split("=",$_) } split(",",$line);
[РЕДАКТИРОВАНИЕ для включения]
Другое предлагаемое решение (который проводит две строки):
my %hash;
#The values in %hash can only be accessed by doing exists($hash{$key})
#The assignment only works with '= undef;' and will not work properly with '= 1;'
#if you do '= 1;' only the hash key of $array[0] will be set to 1;
@hash{@array} = undef;
Здесь существует предположение, что самый эффективный способ сделать большой "Массив содержит X?" проверки должны преобразовать массив в хеш. Эффективность зависит от дефицитного ресурса, часто время, но иногда располагайте с интервалами и иногда усилие программиста. Вы, по крайней мере, удваиваете память, использованную путем хранения списка и хеша список вокруг одновременно. Плюс Вы пишете больше исходного кода, который необходимо будет протестировать, зарегистрировать, и т.д.
Как альтернатива, посмотрите на Список:: модуль MoreUtils, конкретно функции any()
, none()
, true()
и false()
. Они все берут блок в качестве условного выражения и списка как аргумент, подобный map()
и grep()
:
print "At least one value undefined" if any { !defined($_) } @list;
Я запустил быстрый тест, загружающийся в половине/usr/share/dict/words к массиву (25 000 слов), затем ища одиннадцать слов, выбранных со всех концов целого словаря (каждое 5000-е слово) в массиве, с помощью и метода массива к хешу и any()
функция из Списка:: MoreUtils.
На Perl 5.8.8 созданных из источника метод массива к хешу работает почти 1100x быстрее, чем any()
метод (1300x быстрее в соответствии с Ubuntu 6.06's упаковал Perl 5.8.7.)
Это не полная история однако - преобразование массива к хешу занимает приблизительно 0,04 секунды, который в этом случае уничтожает эффективность времени метода массива к хешу к 1.5x-2x быстрее, чем any()
метод. Все еще хороший, но совсем не как звездный.
Мое инстинктивное чувство состоит в том, что метод массива к хешу собирается биться any()
в большинстве случаев, но я чувствовал бы себя намного лучше, если бы у меня были некоторые более твердые метрики (много тестовых сценариев, достойных статистических анализов, возможно, некоторый большой-O алгоритмический анализ каждого метода, и т.д.) В зависимости от Ваших потребностей, Списка:: MoreUtils может быть лучшим решением; это, конечно, более гибко и требует меньшего количества кодирования. Помните, преждевременная оптимизация является грехом... :)
В жемчуге 5.10, существует ~~ оператор близко к волшебству:
sub invite_in {
my $vampires = [ qw(Angel Darla Spike Drusilla) ];
return ($_[0] ~~ $vampires) ? 0 : 1 ;
}
Посмотрите здесь: http://dev.perl.org/perl5/news/2007/perl-5.10.0.html
Можно поместить код в подпрограмму, если Вы не хотите, загрязняют Ваше пространство имен.
my $hash_ref =
sub{
my %hash;
@hash{ @{[ qw'one two three' ]} } = undef;
return \%hash;
}->();
Или еще лучше:
sub keylist(@){
my %hash;
@hash{@_} = undef;
return \%hash;
}
my $hash_ref = keylist qw'one two three';
# or
my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;
Если Вы действительно хотели передать ссылку на массив:
sub keylist(\@){
my %hash;
@hash{ @{$_[0]} } = undef if @_;
return \%hash;
}
my @key_list = qw'one two three';
my $hash_ref = keylist @key_list;