Python, I can't find a tutorial to help me with this, the goal is to check that the nested dictionaries of C in this case, match what has been entered in an input, which is exactly CDFG, on top of another problem, show it in its order in a text string. ¨
// This creates the example dictionary //
sobre_ti={}
def aprender(oraciones):
recordar_pal = sobre_ti
for palabra in oraciones.split():
if palabra not in recordar_pal:
recordar_pal[palabra] = {}
recordar_pal = recordar_pal[palabra]
aprender(input("Escribe: A A A A"))
aprender(input("Escribe: B C D F"))
aprender(input("Escribe: D E F G"))
aprender(input("Escribe: C D F G"))
print(sobre_ti)
This is the code I was talking about
def componer(oraciones):
ver_pal = sobre_ti
for palabra in oraciones.split():
if palabra in ver_pal.keys():
print("Verdadero")
else:
print("Falso")
ver_pal = ver_pal[palabra]
componer(input("Dile algo: "))
print(mostrar)
Since it is apparently part of an academic assignment, and it is the site's policy not to resolve this type of question, I will give you some explanations and instructions so that you can try to solve it yourself and see how far you get. If you can't figure it all out at least you'll get to a point where you can show the code with what you've tried and ask a specific question that better fits the use of the site.
Data structure to create
You have provided a diagram to help understand the problem. However, I think it could be even clearer (especially to a programming public) that you show the resulting dictionary, which contains the data structure that will have to be handled. That dictionary is the one that appears in the
print(sobre_ti)
code of the question, and it is as follows (I format it a bit to make it easier to read):Here we see that the complete structure is a dictionary whose keys are the first letter entered by the user, and the values are more nested dictionaries, until finally arriving at an empty dictionary.
If you go through any of the branches, for example the one corresponding to the key
'C'
, the keys that we find (D, F, G) correspond to the letters entered by the user.In this sense there is an "order". Although python dictionaries don't guarantee the order of their keys (i.e. the "main" dictionary has four keys but we can find them in the order A, B, C, D or A, C, D, B, or any other) , once you choose one of its keys, the rest of the dictionaries that are found already have a single key, and the order in which we advance in the structure, deeper and deeper, would be the order you refer to in the question.
How was this structure created?
This is what the function does
aprender()
and it is interesting to stop and understand it, because it is the key for you to implement other functions later, such as the one that verifies if a sequence given as "CDF G" is stored in the structure.An important line is
recordar_pal = sobre_ti
. This does not make a copy of the dictionarysobre_ti
, but instead makes the variablerecordar_pal
and the variable bothsobre_ti
refer to the same (initially empty) dictionary.Then the letters that the user has entered are scrolled. Suppose you have entered "CDE F". The first would be C.
if palabra not in recordar_pal
see if the C is in the dictionaryrecordar_pal
. Since we have seen that this dictionary is the same assobre_ti
and that it is initially empty, it will be true that the "C" is not there, so it will execute:recordar_pal[palabra] = {}
. Now the dictionaryrecordar_pal
already has an entry and therefore it is worth{ 'C': {} }
. Let's also remember that itsobre_ti
is the same dictionary , so we have already added a "first level" key to the desired data structure.recordar_pal = recordar_pal[palabra]
. This makes the variablerecordar_pal
no longer refer to the dictionarysobre_ti
, but to the (currently empty) internal dictionary that is associated with the key'C'
.When iterating to the next letter "D", everything will be repeated, but taking into account that it
recordar_pal
is now the internal empty dictionary. Therefore when you look to see if it contains a "D" you will see that it is not there, and when it is added it will be added to that internal dictionary, so itsobre_ti
will become valid{ 'C': { 'D' : {} }
and it will be preparedrecordar_pal
to refer to the new internal empty dictionary.This builds the nested structure.
How to check if a sequence is in the dictionary?
And we come to the task that you have to solve. The idea is to use a helper variable like the
recordar_pal
one used inaprender()
that starts pointing to the "total" dictionary (sobre_ti
) and that in a loop checks if the first given letter is in that dictionary. If it is not, it can be returnedFalse
indicating that it is not. If it is, then that helper variable is reassigned to point to the internal dictionary, and the loop repeats.If we exhaust all the given letters and we haven't returned False yet, then they were all there. In that case it returns
True
.Like "print in order"
This task is not clearly defined. You say that you have to print "in order", and I assume you mean the nesting order. But it's not clear if you want to print just the branch being checked (which would be as simple as printing letters as you check), or if you need to print the entire tree. In the second case you could use recursion, but maybe it's a concept you don't know yet. In any case, it is not clear if the internal dictionary can contain branches (for example, if when creating it the string "AAA A" was used and then "AAB B", in which case the dictionary would have this:
If such a structure were possible, what should the result of "print it in order" look like? Should I output "AAAA" "AABB"?
Extension
The user has added the following code as proof of what they are trying to do:
This is already very close to what was requested, but the logic is backwards. It's not about checking if a letter is between the keys and then setting "True" (because "True" should mean that all the letters have been found in order). However, it is correct that if a letter is not found, it can be said "False", since it is enough for one to fail.
Therefore the logic would be: Check if a letter is between the keys. If it is not, we can return
False
(it is better to return results than to print them, so that the function is more useful). But if it is, we can't return yetTrue
, we need to keep checking the next letters. Only if we have already exhausted all the letters will we be able to returnTrue
, since this case will only occur if it had not been returned beforeFalse
and therefore it is the case in which all the letters have been found.So:
Solution to "print in order"
This can be more complex because there may be forks in the graph, like the one shown above after the user entered "AAA A" and then "AAB B".
I think the simplest implementation (in the sense that the code is very short, but not in the sense that it is easy to understand) is to make a recursive function.
A recursive function is one that calls itself to complete the job. The way to think about them is "What if I had a function that knew how to print the tree from one of its intermediate nodes down? How could I make use of that function to print the entire tree?" So you program assuming that function exists, and you reason as follows:
And the magic of recursion is that this hypothetical function will be precisely the one we are writing, which will call itself.
Recursion is a difficult concept to understand, and it is also difficult to see how it works even if you have the solution in front of you. I offer you one possible implementation, but perhaps others are possible. This is what occurred to me.
The idea is that the function is passed a tree and a string. The tree must be understood as a "sub-tree" (ie everything from one of its intermediate nodes downwards). May contain branches. The string, which I'll call the "prefix", contains the names of all the nodes from the root to the node that is the subtree.
For example consider this structure:
And imagine that we want to print in branch "D" the subtree whose key is "E", that is, a subtree that contains
{'F': {'G': {}}}
. Then the function that we are about to write would receive as a tree to display{'F': {'G': {}}}
and as a prefix string"DE"
(because we have reached that sub-tree traversing first "D" and then "E").What should the function do with that data if we could make use of another one that is capable of printing a sub-tree if we pass it that sub-tree and a prefix? So I would call that function passing it a smaller sub-tree (
{'G': {}}
) and a longer prefix: "DEF". And this is the recursive call to itself.The trivial case, when the arriving tree is empty, is to simply print the prefix-string.
Enough preamble, this is the implementation:
As you can see, the function calls itself without doing any printing. Let the called function be the one to do that print. The print will occur when the end of a branch, the empty dictionary, has been reached. Then the "prefix" will be printed that will contain the keys of all the dictionaries through which it has been passed.
Let's see if it works. First we prepare an example:
We have a case with a fork. We call our function (note that in the first call we did not pass a prefix, so it will take the default value
""
, which is perfect because we have not yet traversed any node when we want to print from the root)Departure:
It worked! To understand how it has worked, I recommend that you use a debugger and run the function step by step, examining what it receives as a parameter each time in
arbol
and inprefijo
, so you can understand recursion.