Какова лучшая структура данных в Perl для хранения табличных данных?
У меня есть таблица со следующими данными
1.1.1.1 routerA texas
2.2.2.2 routerB texas
3.3.3.3 routerC california
Какова лучшая структура данных в Perl для хранения этих данных? Я думаю о сохранении в хэш хэш с IP-адресом в качестве ключа
1.1.1.1
routerA => texas,
2.2.2.2
routerB => texas,
3.3.3.3
routerC => california
Но если я хочу получить все IP-адреса в Техасе, моя структура данных может быть недостаточно гибкой. Есть ли лучший способ сохранить это, если я забочусь обо всех IP-адресах в Техасе?
3 ответа
Чистый Perl определенно подходит для этой задачи.
Думайте о таблице как о массиве записей. В Perl говорят, что это массив ссылок на хеш. (Время от времени может применяться AoA, помните TIMTOWTDI)
Ключи каждой хэш-ссылки соответствуют имени столбца / поля, а значения будут, ну, значениями для этой конкретной записи.
Преобразование примера OP в структуру данных:
my @data = (
{
ip => '1.1.1.1',
router => 'routerA',
state => 'texas',
},
{
ip => '2.2.2.2',
router => 'routerB',
state => 'texas',
},
{
ip => '3.3.3.3',
router => 'routerA',
state => 'california',
}
);
Теперь самое интересное:
# Give me all IPs in Texas
my @ips_in_texas = map $_->{ip},
grep { $_->{state} =~ /texas/i }
@data;
# How many states does the data cover?
use List::MoreUtils 'uniq';
my $states_covered = uniq( map $_->{state}, @data );
# How many unique IPs in each state?
my %ips_by_state;
$ips_by_state{ $_->{state} }{ $_->{ip} }++ for @data;
print "'$_': ", scalar keys %{ $ips_by_state{$_} }, "\n" for keys %ips_by_state;
Реакция коленного рефлекса, которую я часто получаю, когда я предлагаю эту структуру данных, основана на ее жажде памяти. Честно говоря, это не будет проблемой, если вы не имеете дело с миллионами записей. И если это так, то СУБД - это решение для заточки карандашей, которое вы ищете, а не Perl.
Я знаю, это не Perl... но как насчет таблицы SQLite в памяти? Быстрый, гибкий, портативный и даже устойчивый. Там можно сделать гораздо более сложные вещи, а потом искать все IP-адреса в Техасе...
Ваше предложение использовать хэш хэшей с IP-адресом в качестве ключа - именно то, как я бы это сделал. Однако вам также придется создать отдельный, вторичный хэш перекрестных ссылок, в котором состояния (например, Техас) являются ключами, а IP-адреса - данными. Во вторичном хэше каждое состояние является ключом, а соответствующее значение само является хэшем. Во внутренних хешах ключи - это IP-адреса, а значения - это фиктивные значения, обычно это значение 1.
В вашем примере, вот вторичный хэш перекрестных ссылок:
california
{ 3.3.3.3 => 1 },
texas
{ 1.1.1.1 => 1, 2.2.2.2 => 1 }
Вы можете написать короткую подпрограмму / функцию / блок, которая строит вторичный хеш из первичного. Это немного сложнее, если набор данных большой и часто обновляется, но идея та же.
Вам будет проще написать код, который выполняет все вышеперечисленное, если вначале вы поймете, что Perl почти слишком симпатичный, но, тем не менее, довольно удобный инструмент автовификации: смотрите manpages perlreftut и perlref.