Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Как получить доступ к сложной структуре


Автор: Wardrag 1.10.2013, 11:33
Имеется структура вида: 

Код

my $struct = {country_id => 1, towns => [{town_id => 10, text => 'Austria'}]};


Она описывает структуру стран и городов. В каждой стране свой город/города.
Хочу проверить, существует ли айди с конкретным городом перед тем, как его добавить в эту структуру.
В хэш городов добавляю так (проверил через Dumper - правильно)\:

Код

$struct->{towns}-[1] = {town_id => 11, text = 'Belgium'};


Но совершенно не понимаю, как мне искать город по айди, если его нет, и добавить его в хэш.
В будущем надо будет по аналогии искать по айди страну, и, если её нет, добавлять тоже, но уже в первый хэш(их же два).
Скажите, пожалуйста, как это сделать ?
Очень интересует именно такая структура.

Автор: krypt3r 1.10.2013, 11:53
Код

for (@{$struct->{'towns'}})
{
    if ($town_id == $_->{'town_id'})
    {
        # найдено, что-то сделать
    }
    else
    {
        # не найдено, сделать что-то другое
    }
}

PS. У вас странная структура. Что у вас делают названия стран в элементе towns (города)?

Автор: Wardrag 1.10.2013, 11:54
Придумал, как смог : ). А как оптимальнее было бы ?

Автор: krypt3r 1.10.2013, 12:01
Ну что-то типа такого
Код

{
    country_id => 1,
    country_name => 'Австрия',
    towns => [
        {town_id => 10, text => 'Вена'},
        {town_id => 11, text => 'Грац'},
        {town_id => 12, text => 'Зальцбург'},
        ...
    ]
};

Автор: Wardrag 1.10.2013, 12:14
Хм, не понимаю, - как вообще 
Код
@{$struct->{'towns'}
 может работать ? @{$var} -  ссылка на массив, после чего идет ссылка на хеш towns...
Я бы начал так: 
Код

$struct->{towns}->[0]->{town_id}...
...
Я так понимаю, вы ссылаетесь сразу на 
Код

[{town_id => 10, text => 'Austria'}]
 ?
И ещё: как так работает цикл for, что ему не нужно знать число элементов ? Я думал, что всегда нужно сперва их узнать, а потом вести перебор...
Все примеры, что я видел, перебирали через foreach


Добавлено через 6 минут и 36 секунд
Кажется, начинаю понимать:

@{$arr} - ссылка на массив
%{arr} - ссылка на хэш

Они нужны, чтобы удобно делать перебор

Автор: krypt3r 1.10.2013, 12:31
Цитата

@{$var} -  ссылка на массив, после чего идет ссылка на хеш towns

Не так. Это операция разыменования ссылки на массив
Цитата

@{$struct->{'towns'}}

for/foreach-у нужен массив, а не ссылка на него. Тут явно происходит разыменование массива, лежащем в towns. Каждый элемент массива — это хэш типа {town_id => 10, text => 'Austria'}.
Цитата

И ещё: как так работает цикл for, что ему не нужно знать число элементов ? Я думал, что всегда нужно сперва их узнать, а потом вести перебор...
Все примеры, что я видел, перебирали через foreach

foreach — это синоним for с вытекающей отсюда взаимозаменяемости. Замените в моем коде for на foreach, если вам так более наглядно будет.
Код

foreach my $tmp_town (@{$struct->{'towns'}})
{
    if ($town_id == $tmp_town->{'town_id'})
    ...
}

Или так можно написать
Код

my @arr = @{$struct->{'towns'}};
my $count = count @arr;
my $i;
for ($i = 0; $i < $count; $i++) {...}

Или вот так
Код

for my $i (0 .. $count - 1) { ... }

Выбирайте вариант, короче, более читабельный для вас.
PS. Если у вас цель — разобраться со сложными структурами данных в перле (хэш хэшей, массив хэшей, хэш массивов и т.д.), то посоветую почитать, например, "Perl. Специальный справочник" Стивена Холзнера. Там в главе "Структуры данных" они рассмотрены

Автор: Wardrag 1.10.2013, 12:59
В инете кучу материалов просмотрел, но так и не разобрался сам, а с Ваши слов и объяснений вроде как понял.
Огромное спасибо ))))).

Автор: krypt3r 1.10.2013, 13:05
Да не за что. Пост выше, кстати, немного поредактировал

Автор: Wardrag 1.10.2013, 13:50
Хм, возникла проблема - добавить элемент в хэш, причем самый первый struct
Запушить выходит нельзя ничего, кроме массива, дык как же тогда добавить его ?) ( в самом моем первом посте)
Смысл: создать элемент с ещё одним id country_id=2 и т.д.
Пытаюсь добавить целый хэш ( дошло, тупо скопировал его и сменил параметры), а оно выдает ошибку мол ссылка не на массив.
Выходит, так нельзя ?

Автор: krypt3r 1.10.2013, 14:17
В $struct вы не можете добавить ключ country_id, ибо он уже существует. Нужно переделывать $struct в массив хэшей типа
Код

{
    country_id => 1,
    country_name => 'Австрия',
    towns => [
        {town_id => 10, text => 'Вена'},
        {town_id => 11, text => 'Грац'},
        {town_id => 12, text => 'Зальцбург'},
        ...
    ]
},
{
    country_id => 2,
    country_name => 'Бельгия',
    towns => [
        {town_id => 110, text => 'Брюссель'},
        {town_id => 111, text => 'Антверпен'},
        {town_id => 112, text => 'Брюгге'},
        ...
    ]
},
...

Если я неправильно понял, покажите код и желаемую структуру данных. 

Автор: Wardrag 1.10.2013, 14:32
У меня country_id связан с  массивом хэшей towns
Вот так вот: country_id => towns => [{ тут города страны } ]  (так получилось после добавления нового country_id)
Добавил обычным присваиванием в хэш.
Но из-за этого нужно сначала в цикле набивать города, а потом огромный хэш сохранить вмести с городами и новым айди страны, затем меняется айди страны( по возрастанию или с переменной), опять прогоняются города, разумеется, все разные.
Вот что я хочу сделать...

Автор: Wardrag 1.10.2013, 20:22
Написал на email : ). Проверьте, пожалуйста!

Автор: infarch 2.10.2013, 10:03
А вы уверены что не хотите пользоваться базами данных вместо всех эти мегахешей? SQLite поможет отцу русской демократии )

Автор: Grost 2.10.2013, 11:21
Не знаю, правильно ли я понял задачу, но почему не сделать структуру в которой проще будет искать? Т.е. мы делаем не массив хешей, а просто хеш.

Код

country_id => {
    name => 'country name',
    towns => {
        town_id => {
            name => 'town name',
        }
    }
}


таким образом, мы можешь легко и просто доставать нам нужную информацию.

Код

my $struct = { 
    1 => { 
        towns => { 
            10 => { text => 'Austria'},
        } 
    }
};

if ( $struct->{$country_id}->{towns}->{$town_id} ) {
    # такой город есть
    print $struct->{$country_id}->{towns}->{$town_id}->{text}, "\n"; # вывели текст
} else {
    # город не найден
    $struct->{$country_id}->{towns}->{$town_id} = { text => 'new town' }; # добавили город
}





Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)