В Perl, как я создаю хеш, ключи которого прибывают из данного массива?

77
задан tjwrona1992 26 August 2015 в 19:12
поделиться

12 ответов

%hash = map { $_ => 1 } @array;

Это не столь коротко как "@hash {@array} =..." решения, но те требуют, чтобы хеш и массив уже были определены где-то в другом месте, тогда как этот может взять анонимный массив и возвратить анонимный хеш.

То, что это делает, является взятием каждый элемент в массиве, и разделите на пары его с "1". Когда этот список (ключ, 1, ключ, 1, ключевой 1) пары присвоены хешу, нечетные становятся ключами хеша, и четные становятся соответствующими значениями.

114
ответ дан 9 revs 24 November 2019 в 10:46
поделиться

Вы могли бы также хотеть проверить Связь:: IxHash, который реализует заказанные ассоциативные массивы. Это позволило бы Вам делать оба типа поисков (хеш и индекс) на одной копии Ваших данных.

0
ответ дан 24 November 2019 в 10:46
поделиться

Если Вы делаете много набора теоретические операции - можно также использовать Набор:: Скаляр или подобный модуль. Тогда $s = Set::Scalar->new( @array ) создаст Набор для Вас - и можно запросить его с: $s->contains($m).

1
ответ дан zby 24 November 2019 в 10:46
поделиться

Вы могли также использовать Perl6:: Соединение .

use Perl6::Junction qw'any';

my @arr = ( 1, 2, 3 );

if( any(@arr) == 1 ){ ... }
2
ответ дан Brad Gilbert 24 November 2019 в 10:46
поделиться

Я всегда думал, что

foreach my $item (@array) { $hash{$item} = 1 }

было, по крайней мере, хорошо и читаемый / удобный в сопровождении.

7
ответ дан Keith 24 November 2019 в 10:46
поделиться

Обратите внимание, что при вводе if ( exists $hash{ key } ) isn’t слишком много работы для Вас (начиная с которого я предпочитаю использовать, вопрос, представляющий интерес является действительно присутствием ключа, а не правдоподобием его значения), тогда можно использовать короткое и сладкое

@hash{@key} = ();
16
ответ дан Aristotle Pagaltzis 24 November 2019 в 10:46
поделиться
@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, и некоторые другие решения поворачивают колеса телеги для создания массива значений для входа в хеш; полностью потраченное впустую усилие).

37
ответ дан user3487205 24 November 2019 в 10:46
поделиться
 @hash{@array} = (1) x @array;

Это - часть хеша, список значений от хеша, таким образом, это получает список-y впереди.

От документы :

, Если Вы смущены тем, почему Вы используете там на части хеша вместо '% ', думают он как это. Тип скобки (квадратный или изогнутый) управляет, является ли это массивом или хешем, посмотревшим на. С другой стороны, начальный символ (' $' или) на массиве или хеше указывает, возвращаете ли Вы сингулярное число (скаляр) или множественный (список).

42
ответ дан Kev 24 November 2019 в 10:46
поделиться

Решение 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;
3
ответ дан Frosty 24 November 2019 в 10:46
поделиться

Здесь существует предположение, что самый эффективный способ сделать большой "Массив содержит 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 может быть лучшим решением; это, конечно, более гибко и требует меньшего количества кодирования. Помните, преждевременная оптимизация является грехом... :)

7
ответ дан arclight 24 November 2019 в 10:46
поделиться

В жемчуге 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

5
ответ дан RET 24 November 2019 в 10:46
поделиться

Можно поместить код в подпрограмму, если Вы не хотите, загрязняют Ваше пространство имен.

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;
1
ответ дан Brad Gilbert 24 November 2019 в 10:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: