domingo, 25 de outubro de 2009

Problema 4.16

Por definição os netos são os filhos dos filhos. Usando o princípio da programação descendente, por camadas de abstracção, admitamos que sabemos com determinar os filhos de alguém. então uma solução para o nosso problema pode ser facilmente equacionada:

01.def netos(dicio,progenitor):
02.    """ Lista netos."""
03.    desc1 = filhos(dicio,progenitor)
04.    if desc1:
05.        net = []
06.        for elem in desc1:
07.            desc2 = filhos(dicio,elem)
08.            if desc2:
09.                net = net + desc2
10.    else:
11.        return []
12.    return net


Na linha 3, calculamos os filhos. Como o faremos em concreto depois se verá. Para ter netos é preciso que o progenitor tenha ... filhos (teste na linha 4)! Caso tenha, usamos o padrão acumulador para determinar os filhos de cada filho e juntar tudo numa lista chamada net (linhas 5 a 9). Passemos então ao problema de saber quem são os filhos de alguém. Questão fácil dada a organização do dicionário.

1.def filhos(dicio,progenitor):
2.    """ lista dos filhos."""
3.    res= dicio.get(progenitor,None)
4.    return res


Resolvido o problema pensemos um pouco mais. Não seria interessante uma solução que seguisse de perto a definição? Claro que sim. Algo como:

1.def netos(dicio ,progenitor):
2.    """ Lista dos netos."""
3.    netos = filhos(dicio,filhos(dicio,progenitor))
4.    return netos


Mas não funcionaria. Porquê? Bem, um olhar atento diz-nos porquê: a função filhos recebe uma cadeia de caracteres (um nome) e devolve uma lista (a lista dos filhos). Assim, na segunda vez que se utilizasse filhos daria erro pois estava a ser tentado executar a definição com um argumento lista em vez de uma cadeia de caracteres. A solução passa por fazer com que a definição filhos funcione com listas de cadeias de caracteres. Este é um exemplo de outro mecanismo importante para resolver problemas: generalização!

1.def filhos(dicio,lista_progenitores):
2.    lista_filhos = []
3.    for filho in lista_progenitores:
4.        lista_filhos.extend(dicio.get(filho,[]))
5.    return lista_filhos


Notar o uso do método extend, pois agora vamos acumular numa lista elementos que, também eles aparecem em listas. Notar também a necessidade de usar a lista vazia como default do get. O leitor atento dirá: mas agora deixa de funcionar a definição de netos pois no início só há um progenitor!! Mas isso resolve-se facilmente: a primeira chamada de filhos, dentro da chamada de netos tem como segundo argumento uma lista com um elemento: o progenitor. E chegamos à versão completa.

01.def netos(dicio ,progenitor):
02.    """ Lista dos netos."""
03.    netos = filhos(dicio,filhos(dicio,[progenitor]))
04.    return netos
05. 
06.def filhos(dicio,lista_progenitores):
07.    lista_filhos = []
08.    for filho in lista_progenitores:
09.        lista_filhos.extend(dicio.get(filho,[]))
10.    return lista_filhos

2 comentários:

  1. seria possível esta resolução, tendo em conta a função filhos dada no enunciado:

    def netos(dicio,progenitor):
    '''Lista dos netos.'''
    fim=list()
    filho=filhos(dicio,progenitor)
    for i in filho:
    neto=dicio.get(i,None)
    fim=fim+neto
    return fim

    ResponderEliminar
  2. Goreti:

    Está quase perfeito! A única questão é que tem que usar:

    neto = dicio.get(i, [])

    e não None. Isto porque, no caso de não haver neto o programa ia tentar concatenar uma cadeia de caracteres com None o que daria erro.

    ResponderEliminar