I dont know what the heck is going on.

I have scene.. idk how to explain it, but here is the thing that i want to achieve:
Return array of files.

I have data. Data is structured as dictionary. Keys are strings and value is array. Array consists of files and directories. Files are strings, while directories are dictionaries with directory as key and value as array of files and dirs.

So atm i have set up so that when i click in the UI a directory, it triggers function:

func on_dir_label_button_down(dir_name):
	print("Button pressed: ", dir_name)
	var lol = file_ops.get_files_from_tree(dir_name,file_ops.current_tree_dic)
	print("retunr: ", lol)
	pass

file_ops = linked instance in the scene tree

The function:

func get_files_from_tree(dir_key, data):
	
	if data is Dictionary:
		var key_v = data.keys()[0]
	
		if key_v == dir_key:
			
			var sorted = get_files_from_arr(data[dir_key])
			return sorted
		else:
			get_files_from_tree(dir_key,data[key_v])
	else:
		for f in data:
			if f is Dictionary:
				get_files_from_tree(dir_key,f)
		pass

Is recursive.

So this is what i got, the folder i parse looks like this.

I press guru button/directory to get files.

The function break correctly returned the files:

But the break at the button press function call where it should return the values return nulls

Why?

  • xyz replied to this.
  • kuligs2 Yes, the else is redundant. An if-statement will always have exactly two possible outcomes. The part after if (if the condition is true) and the part after else (if the condition is false). If it is not one it is the other. In the case of the first if statement, the function will always return if the condition is true (the only possible execution path ends with a return). The execution of a function ends when it hits a return. That means any code after the if will only be executed if the condition is false (i.e. the else part).

    To illustrate, the following two pieces of code are functional identical:

    if a:
        return
    else:
       do something else
    if a:
        return
    do something else

    Therefore else is redundant here.

    As for the problems with your code, you only need to prefix all free standing calls to get_files_from_arr with a return. That gets you almost to the correct solution. The only problem left will be the last case (the if in the for loop never succeeding).

    Edit: Actually not sure about the last get_files_from_arr. That indeed may require accumulation and then return.

    kuligs2 Print what the recursive function does, and also declare its return type.

      func get_files_from_tree(dir_key, data):
      	
      	if data is Dictionary:
      		var key_v = data.keys()[0]
      	
      		if key_v == dir_key:
      			
      			var sorted = get_files_from_arr(data[dir_key])
      			return sorted
      		else: # unrelated, but this else is redundant
      			get_files_from_tree(dir_key,data[key_v]) # if code gets into this branch, function exits without returning an explicit value, therefore null
      	else: # unrelated, but if the line above is fixed this else also becomes redundant.
      		for f in data:
      			if f is Dictionary:
      				get_files_from_tree(dir_key,f) # if code gets into this branch, function exits without returning an explicit value, therefore null
      		# if code gets to this point without the if above succeeding, function exits without returning an explicit value, therefore null
      		pass

        xyz But i already showed you what it returned in the first post.
        It should have stopped at the:

        which is correct return.

        But in the button down function it returns null

        Here are the break points. Step by step.

        I cant declare return type, sometimes its array sometimes its dictionary.

        Zini First else is not redundant, The data can be dictionary or array. If dictionary and first key matches dir_key, then you return the values, else, you go deeper into the values and search for a dictionary there, that this the second else statement, we parse the array and look for dictionary with the dir_key key.

        EDIT:

        Ah, i think i got it, the second else returns null because it launches another "thread/process" by calling the function... hmm so i need to somehow capture all the data inside that else statement.

          kuligs2 Yes, the else is redundant. An if-statement will always have exactly two possible outcomes. The part after if (if the condition is true) and the part after else (if the condition is false). If it is not one it is the other. In the case of the first if statement, the function will always return if the condition is true (the only possible execution path ends with a return). The execution of a function ends when it hits a return. That means any code after the if will only be executed if the condition is false (i.e. the else part).

          To illustrate, the following two pieces of code are functional identical:

          if a:
              return
          else:
             do something else
          if a:
              return
          do something else

          Therefore else is redundant here.

          As for the problems with your code, you only need to prefix all free standing calls to get_files_from_arr with a return. That gets you almost to the correct solution. The only problem left will be the last case (the if in the for loop never succeeding).

          Edit: Actually not sure about the last get_files_from_arr. That indeed may require accumulation and then return.

            Zini Ok, lost in translation, i read that the whole else statement path was redundant... i understand what you mean now, its just easier for me to follow through the code if i explicitly write out all the small details.

            For the problem i had, yes, i just had to return the function on all paths, and in the last statement, i have to aggregate all paths?

            func get_files_from_tree(dir_key, data):
            	var result_arr : Array
            	if data is Dictionary:
            		var key_v = data.keys()[0]
            	
            		if key_v == dir_key:
            			
            			var sorted = get_files_from_arr(data[dir_key])
            			return sorted
            	
            		return get_files_from_tree(dir_key,data[key_v])
            	
            	for f in data:
            		if f is Dictionary:
            			var result = get_files_from_tree(dir_key,f)
            			if result:
            				result_arr.append_array(result)
            	return result_arr

            So now the function returns array with values or empty array if the directory has no files.

            EDIT:

            Ah.. now the problem is that it returns only the first path it finds.

            If i press the second nested guru dir, then it still returns the first guru dir in results.

            Maybe i need to keep track of depth levels of the directory...??

            kuligs2 But i already showed you what it returned in the first post.

            I don't need anything shown. I see what is happening. Show it to yourself 😃. I didn't said to print what it returns. I said to print what it internally does. And should you declared its return type, you would have noticed that the engine is warning you that the function has code paths that don't return anything.

            As a homework, you could write a non-recursive version of this function. Leave the recursion to people who prefer confusing unreadable code.

              xyz But i can write non-recursive because i have to look for the key in n-depth level, so the function has to do the same thing n-times..

              Maybe i need to structure data differently in the beginning Now it is like:

              {
                  "/": [
                      {
                          "dir1": [
                              "1.txt",
                              "2.txt",
                              {
                                  "dir2": [
                                      {
                                          "dir3": [
                                              {
                                                  "dir4": [
                                                  ]
                                              },
                                              {
                                                  "dir5": [
                                                  ]
                                              },
                                              {
                                                  "dir6": [
                                                      "f(1).txt",
                                                      "f(2).txt",
                                                      "f(3).txt",
                                                      "f(4).txt",
                                                      "f(5).txt",
                                                      "f(6).txt",
                                                      {
                                                          "dir7": [
                                                          ]
                                                      }
                                                  ]
                                              },
                                              {
                                                  "dir8": [
                                                  ]
                                              }
                                          ]
                                      }
                                  ]
                              }
                          ]
                      },
                      {
                          "dir9": [
                          ]
                      },
                      {
                          "dir10": [
                          ]
                      },
                      "f1.txt",
                      "f2.txt",
                      "f3.txt"
                  ]
              }

              I was thinking it would be cheap to store data this way.. since the parse function does the same recursive to get the dir-tree data in the first place..

              But as the last post i posted / edited, the problem now is how to pick a correct depth level when the "key/dir_name" is the same value.

              I could inject the depth level inside the dictionary as a second key, but maybe there is better way to represent file lists/dir tree in the data.. ?