Construa hash de listas, como para "todas as tags para id" com perl dbi

Construa hash de listas, como para "todas as tags para id" com perl dbi

Pesquisei nos dbidocumentos e pesquisei no Google, mas não consegui descobrir se havia uma maneira nativa (dbi) de criar um hash de listas. O mais próximo que consigo pensar é fetchall_hashrefque isso substitui os resultados, dando-me apenas o que foi o último par. Para esclarecer, minha tabela é uma lista de pares de algo como “id, tag”. Desejo agrupar todas as linhas por id e retornar um hash onde a chave é o id e o "valor" é uma (ref to) a lista de todas as suas tags. Então, no caso de:

id1, tag1
id1, tag2
id2, tag3
id2, tag1

Eu quero obter:

{'id1' => ['tag1', 'tag2'],
 'id2' => ['tag3', 'tag1'] }

Isso é possível? Caso contrário, qual é a melhor (mais eficiente) maneira de fazer isso de forma não nativa? A abordagem óbvia seria apenas fazer uma combinação fetchall_* + push(), mas existe uma maneira melhor?

Responder1

Esta é minha abordagem atual:

my $ret = {};
foreach (@{ $sth->fetchall_arrayref(  ) }) { # returns ref to array
    push  @{ $ret->{ $_->[0] } }, $_->[1] ;
    }
return $ret;

Caso seja útil para alguém aí, enquanto esperamos para ver se existe uma maneira melhor de fazer isso.


Editar:

Encontrei outra abordagem, que é usar GROUP_CONCATno MySQL para as "tags", unidas com um caractere único, que depois você split()em perl. A consulta seria algo como:

SELECT id, GROUP_CONCAT(tag, '|')
FROM mytable
GROUP BY tag

Então em perl:

my $ret = {};
foreach (@{ $sth->fetchall_arrayref(  ) }) { # returns ref to array
    push  @{ $ret->{ $_->[0] } }, split("|", $_->[1]) ;
    }
return $ret;

Código não testado, portanto, avisos padrão se aplicam.

A única vantagem que vejo é que isso retorna menos linhas do banco de dados e, portanto, você tem menos iterações do foreach. Talvez alguém possa traçar o perfil deste código e nos informar se há alguma diferença significativa de velocidade nas abordagens.

informação relacionada