Модераторы: korob2001, ginnie

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Поиск в хеше с его преобразованием? 
:(
    Опции темы
Suppir
Дата 21.4.2010, 08:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 588
Регистрация: 20.4.2009

Репутация: нет
Всего: нет



Есть хеш %all вида:

12 3 = 1
12 4 = 1
1245 = 1
1236 = 1
123 6 8 89 =1
...

Есть строка $a="1   2    3";


Как сделать функцию, которая будет проверять наличие строки $a в хеше %all,
не учитывая пробелы в строке и хеше? Однако значения в хеше нельзя менять навсегда, так как он дальше используется с этими пробелами. Проблема в том, что хеш очень большой и строки в нем длинные. Необходимо оптимизировать поиск.

Это сообщение отредактировал(а) Suppir - 21.4.2010, 08:21
PM MAIL   Вверх
dva300
Дата 21.4.2010, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 220
Регистрация: 17.2.2010
Где: Москва

Репутация: -1
Всего: 1



Цитата(Suppir @ 21.4.2010,  08:21)
Есть хеш %all вида:

12 3 = 1
12 4 = 1
1245 = 1
1236 = 1
123 6 8 89 =1
...

Есть строка $a="1   2    3";


Как сделать функцию, которая будет проверять наличие строки $a в хеше %all,
не учитывая пробелы в строке и хеше? Однако значения в хеше нельзя менять навсегда, так как он дальше используется с этими пробелами. Проблема в том, что хеш очень большой и строки в нем длинные. Необходимо оптимизировать поиск.

хм....

Код

my %all = (
            "123" => 1,
            "1 23" => 2,
            "12 3 43" => 3,
            "12 333" => 4,
            "1254 3" => 5,
            );
my $per='1254 3';
print "$per exist in \%all\n" if (grep($_=~/^$per$/,keys(%all)));    

--------------------
Участник движения Культура Вождения
PM   Вверх
amg
Дата 21.4.2010, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Код
my %all = (
            "123" => 1,
            "1 23" => 2,
            "12 3 43" => 3,
            "12 333" => 4,
            "1254 3" => 5,
            );
my $a="1   2    3";

print "OK\n" if is_string($a, \%all);

sub is_string {
  my ($a, $all) = @_;
  $a = join '\s*', split ' ', $a;
  $a = qr($a);
  while ((my $key) = each %$all) {
    $key =~ $a && print "$key\n"; # For debug
    #$key =~ $a && return $key;
  }
  return undef;
}


PM MAIL   Вверх
Suppir
Дата 23.4.2010, 09:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 588
Регистрация: 20.4.2009

Репутация: нет
Всего: нет



amg ближе всех оказался к истине!
PM MAIL   Вверх
amg
Дата 23.4.2010, 09:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(Suppir @  23.4.2010,  09:23 Найти цитируемый пост)
amg ближе всех оказался к истине!
А в чем же настоящая истина? smile

PM MAIL   Вверх
odmink0
Дата 23.4.2010, 11:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 7.4.2010
Где: Рязань

Репутация: нет
Всего: нет



Хочу заметить, что решение amg находит даже те ключи хеша, которые не равны строке $a (с условием, что из неё и из ключа уберут пробелы), а содержат эту строку. То есть если $a='123', то найдутся и ключи, равные '12345' и '555123555'.
Чтобы обеспечить равенство, можно использовать:
Код

$a = qr(^$a$);


Кроме того не вижу смысла использовать each(), когда можно использовать keys() - раз уж мы все равно ведём поиск только среди ключей.
PM MAIL Jabber   Вверх
amg
Дата 23.4.2010, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(odmink0 @  23.4.2010,  11:00 Найти цитируемый пост)
Кроме того не вижу смысла использовать each(), когда можно использовать keys() - раз уж мы все равно ведём поиск только среди ключей.
Цитата(Suppir @  21.4.2010,  08:21 Найти цитируемый пост)
Проблема в том, что хеш очень большой и строки в нем длинные.
keys создаст дополнительный массив из ключей хэша, а это лишний расход и памяти, и времени.
PM MAIL   Вверх
NuINu
Дата 24.4.2010, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 131
Регистрация: 19.7.2008

Репутация: 5
Всего: 6



какая глупость, хеш для того и создаеться что бы осуществлять быстрый доступ к элементам по индексу, а вы не пойми что из него сделали.

нужно просто изменить структуру хеша, и тогда все будет находиться по простому exist
PM MAIL   Вверх
amg
Дата 24.4.2010, 12:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(NuINu @  24.4.2010,  12:42 Найти цитируемый пост)
какая глупость
А Вы предложите умное решение, а то рекомендация "просто изменить структуру хеша" не очень информативна smile

PM MAIL   Вверх
KSURi
Дата 24.4.2010, 17:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 20
Всего: 27



Цитата(amg @  23.4.2010,  12:04 Найти цитируемый пост)
keys создаст дополнительный массив из ключей хэша, а это лишний расход и памяти, и времени. 

Ну создаст он временный массив с указателями на строки. Ничего вы из-за этого не потеряете. А со временем, так вообще фигня какая-то.

Мой вариант простой и без выпендрежа)
Код

sub foo {
    my ( $str, $hash ) = @_;

    $str =~ s{\s}{}g;

    for my $k ( keys %$hash ) {
        $k =~ s{\s}{}g;
        return 1 if $str eq $k;
    }

    0;
}



--------------------
Died at Life.pl line 21
PM Jabber   Вверх
amg
Дата 26.4.2010, 07:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Господа! Ну почему вам так не нравится функция each? ^ smile

Еще раз процитирую кусочек самого первого поста:
Цитата(Suppir @  21.4.2010,  08:21 Найти цитируемый пост)
Проблема в том, что хеш очень большой и строки в нем длинные. Необходимо оптимизировать поиск.

Сейчас потестировал на хэше из 2_500_000 элементов с длиной ключей 70 символов.
Функция KSURi на моем компьютере работает 11 с и скрипт требует 630 М памяти. Если в этой функции просто заменить
for my $k ( keys %$hash ) {
на 
while ( (my $k) = each %$hash ) {
то будет 9 с и 350 М.
Выигрыш по времени действительно невелик, но по памяти существенен.

Я, может неправильно, понял топикстартера так, что нужно искать не совпадение строки с ключом (без пробелов), а наличие подстроки в ключе. Пэтому постарался сделать так, чтобы в цикле было только одно регулярное выражение (видимо, подготовительные операции для этого публика и приняла за выпендреж). Чтобы определять наличие подстроки в функции KSURi, туда нужно внести еще одно регулярное выражение, т.е. $str eq $k заменить на $k =~ /$str/, а это даст еще лишние 2 с.

Кстати, KSURi, судя по прибавке памяти, получается (перл 5.8), что keys создает все же массив ключей, а не массив ссылок на них. Хотя в данной ситуации ( for (keys %hash) ), казалось бы, можно было ограничиться массивом ссылок. Может, в более новых перлах так?
PM MAIL   Вверх
Suppir
Дата 26.4.2010, 11:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 588
Регистрация: 20.4.2009

Репутация: нет
Всего: нет



Ребята, я сделал эту функцию без хеша. Просто перебором по двум массивам и сравнением измененных элементов этих массивов.
Вариант с хешем отбирал очень много оперативки.

PM MAIL   Вверх
NuINu
Дата 26.4.2010, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 131
Регистрация: 19.7.2008

Репутация: 5
Всего: 6



Цитата(amg @  24.4.2010,  10:58 Найти цитируемый пост)
А Вы предложите умное решение, а то рекомендация "просто изменить структуру хеша" не очень информативна smile

элементарно
Код

#!/usr/bin/perl -w


use strict;
use Data::Dumper;

my %all = (
    "123" => 1,
    "1 23" => 2,
    "12 3 43" => 3,
    "12 333" => 4,
    "1254 3" => 5,
);

my $a="1   2    3";
my $b="1   1    3";

my %s_all = make_searh_hash(\%all);
#print "Dump search: ", Dumper(\%s_all), "\n";
print "find '$a' OK\n" if has_string($a, \%s_all);
print "find '$b' OK\n" if has_string($b, \%s_all);


sub make_searh_hash {
    my $p_all = shift;
    my %all = %$p_all;
    my %s;
    while ((my $key) = each %all) {
        $key = join '', split '\s*', $key;
        $s{$key} = 1;
    }
    return %s;
}

sub has_string {
    my ($a, $all) = @_;
    $a = join '', split '\s*', $a;
    return exists $all{$a};
}



PM MAIL   Вверх
amg
Дата 26.4.2010, 14:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1145
Регистрация: 3.8.2006
Где: Новосибирск

Репутация: 38
Всего: 50



Цитата(NuINu @  26.4.2010,  14:13 Найти цитируемый пост)
элементарно
Как выяснилось, даже один хэш не влазит в память, а Вы предлагаете завести еще один такой же. smile

Но Вы безусловно правы в том, что нужно было с самого начала менять подход к решению задачи... Тут упрек топикстартеру: прежде чем просить о помощи, нужно было подумать, ведь потребляемую хэшем память можно прикинуть заранее.
PM MAIL   Вверх
Suppir
Дата 27.4.2010, 08:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 588
Регистрация: 20.4.2009

Репутация: нет
Всего: нет



Я знал, что хеш много памяти кушает, но не предполагал, что настолько smile

Это сообщение отредактировал(а) Suppir - 27.4.2010, 08:14
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0870 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.