LINUX.ORG.RU

Tied-что-нибудь для автоудаления из списка по принципу ON DELETE CASCADE

 , ,


0

2

Нужно так:

Есть список, в нём лежат ссылки на элементы хэша:

my $h={split //,q(abcdefghijklmn)};
my $a=[map \$h->{$_}, keys $h] ;

При удалении каких-то элементов из хеша хотелось бы, чтобы и в $a удалялись элементы... автомагически.

delete @{$h}{qw(a c m g)};
print Dumper $a;

Однако же:

$VAR1 = [
          \'f',
          \'d',
          \'l',
          \'b',
          \'h',
          \'n',
          \'j'
        ];

Если не удалять, а делать undef элементов хеша - ситуация уже становится полегче (можно виртуозно грепать список), вот только одна беда: таких списков over дофига, т.е. на самом деле $a является «одним-из-миллиарда» элементов другой структуры данных - и при удалении элементов из хеша проходить по всем таким спискам - это эпичнейший геморрой.

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

А есть ещё какие-то варианты? Как обеспечить некоторую связность структур данных, при которой если удаляются элементы из одной структуры - они исчезают из другой тоже?

★★★★★

$a плохое имя для локальной переменной.

level1 ()
Ответ на: комментарий от level1

Это же пример, я его в perl -e выполняю.

Месье имеет сказать что-нибудь по теме вопроса?

DRVTiny ★★★★★ ()
Ответ на: комментарий от DRVTiny

Я вашего обвеса не вижу, но $a особая переменная, могут возникнуть непредсказуемые ошибки. По теме: сделать третью стурктуру, содержащую ссылки на элементы первой и второй.

level1 ()
use Scalar::Util qw/weaken/;

my $h={split //,q(abcdefghijklmn)};
my $l=[map \$h->{$_}, keys $h];
weaken($_) for(@$l);
pru-mike ★★ ()
Ответ на: комментарий от pru-mike

Развивая идею можно с помощью Variable::Magic поставить хук на destroy переменной, который будет удалять нужный элемент массива с помощью splice.

Olegymous ★★ ()
Ответ на: комментарий от Olegymous

А как он его удалит, если неизвестен номер элемента?

DRVTiny ★★★★★ ()
Ответ на: комментарий от DRVTiny

Ну а кто мешает передать индекс?

Что-то типа того (пcевдокодом)

my $index = Index->new();
my $l; $l=[map { my $i = $index->inc(); on_destroy($h->{$_}, sub { splice @$l, $index->withdraw($i), 1 }); \$h->{$_} } keys $h];

package Index;

sub inc {
# возврат следующего индекса
# и также складываем его во внутреннюю переменную - массив
# дабы сохранить верность индексов после удаления элементов
}

sub withdraw {
# возвращает правильный индекс по переданному из внутреннего массива
# и уменьшает в нем все элементы правее на 1
# что и делает возвращаемый индекс правильным 
}

Olegymous ★★ ()
Последнее исправление: Olegymous (всего исправлений: 1)
Ответ на: комментарий от Olegymous

Это уже немного противоречит принципам clear, simple, straightforward оно же KISS...

DRVTiny ★★★★★ ()
Ответ на: комментарий от DRVTiny

Две ремарки относительно подобных модулей.

1. Они меняют базовые концепции языка. По сути вы уже пишите не совсем на перле.

2. Если вы tie считаете извращением, то просмотр внутренностей Util::Scalar, например, вряд ли улучшит вам настроение.

level1 ()
Ответ на: комментарий от DRVTiny

Так и пиши, что не осилил :D

Всё это можно завернуть в функцию make_dependent_array($hashref), которая и возвратит тебе прокачаный arrayref.

Olegymous ★★ ()
Ответ на: комментарий от Olegymous

Появилось время. Вот, что получилось

use strict;
use Variable::Magic qw/wizard cast/;
use Scalar::Util 'weaken';
use Data::Dumper;

my %h = qw(a 1 b 2 c 3);

my $a = make_dependent_array(\%h);
print Dumper $a;

for (qw/b a c/) {
	print "deliting ", delete $h{$_}, "\n";
	print Dumper $a;
}

sub make_dependent_array {
	my $hash = shift;
	
	my @array;
	my $index = Index->new;
	
	for (values %h) {
		my $i = $index->inc();
		$array[$i] = \$_;
		weaken $array[$i];
		
		cast $_, wizard(free => sub {
			splice @array, $index->withdraw($i), 1;
		});
	}
	
	\@array;
}

package Index;

sub new {
	bless {
		indexes => [],
		i       => 0,
	}, shift;
}

sub inc {
	my $self = shift;
	
	my $i = $self->{i}++;
	push @{$self->{indexes}}, $i;
	$i;
}

sub withdraw {
	my ($self, $i) = @_;
	
	my $indexes = $self->{indexes};
	for (my $x=$i+1; $x<@$indexes; $x++) {
		$indexes->[$x]--;
	}
	
	$indexes->[$i];
}

Olegymous ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.