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-хэшем, у которого в качестве ключей выступают прямо ссылки на элементы другого хеша. Но... по-моему это уже совсем эпичное извращение.

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

★★★★★

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

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

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

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

Olegymous ★★★
()
Ответ на: комментарий от 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)
Ответ на: комментарий от 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 ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.