### ### algorithmic utility ### extends Object class_name GDBAlgorithm class __SortBy: var prop_name := "" var descending := false func __sort(obj0, obj1): var res = obj0.get(prop_name) < obj1.get(prop_name) if descending: return !res return res ################ # public stuff # ################ func _init() -> void: assert(0, "This class should not be instantiated.") # Packs source code into a small script object, like a lambda in other languages. # This function can then be called by calling the "eval" (or whatever you pass as # fn_name) function of the object. This is especially useful for GDScript functions # like "sort_custom" which take an object and a function as parameters. # # Example: # var names := ["Bob", "Alice", "Elfriede"] # names.sort_custom(GDBAlgorithm.lambda("return name0.substr(1) < name1.substr(1)", ["name0", "name1"]), "eval") # print(names) # prints "[Elfriede, Alice, Bob]" # # @param source The source code of your lambda function. # @param params A list of parameter names your function takes. # @param fn_name The name of the resulting function, defaults to "eval". # @returns An object containing the lambda function as fn_name. static func lambda(source : String, params := [], fn_name := "eval") -> Reference: var script := GDScript.new(); script.source_code = "tool\nextends Reference\nfunc {fn_name}({param_list}):\n\t{source}".format({ "source": source, "param_list": PoolStringArray(params).join(","), "fn_name": fn_name }) var err : int = script.reload() if err == OK: return script.new() else: printerr("lambda: script compilation failed.") return null # Removes elements from a collection only if the specified condition is met. # Takes either an object and a function name or a lambda and a parameter list # as parameters. # # Example 1: # func is_negative(num): # return num < 0 # # func remove_negatives(col): # GDBAlgorithm.remove_if(col, self, "is_negative") # # Example 2: # func remove_negatives2(col): # GDBAlgorithm.remove_if(col, "num < 0", ["num"]) static func remove_if(collection, p0, p1 = null) -> int: if p0 is String: if p1 && !p1 is Array: printerr("remove_if failed: invalid parameters") return 0 var lmb := lambda(p0 as String, p1 as Array if p1 else []) if !lmb: return 0 # errors have already been printed return __remove_if(collection, lmb, "eval") elif !p0 is Object || !p1 is String: printerr("remove_if failed: invalid parameters") return 0 else: return __remove_if(collection, p0, p1) static func sort_by(arr : Array, prop_name : String, descending := false): var comparator := __SortBy.new() comparator.prop_name = prop_name comparator.descending = descending arr.sort_custom(comparator, "__sort") ################# # private stuff # ################# static func __remove_if(collection, object : Object, predicate : String) -> int: if collection is Array: return __remove_if_array(collection, object, predicate) elif collection is Dictionary: return __remove_if_dict(collection, object, predicate) else: var values_to_remove := [] for ele in collection: if object.call(predicate, ele): values_to_remove.append(ele) for ele in values_to_remove: collection.erase(ele) return values_to_remove.size() static func __remove_if_array(array : Array, object : Object, predicate : String) -> int: var removed := 0 for i in range(array.size() - 1, -1, -1): if object.call(predicate, array[i]): array.remove(i) removed += 1 return removed static func __remove_if_dict(dict : Dictionary, object : Object, predicate : String) -> int: var removed := 0 for key in dict.keys(): if object.call(predicate, dict[key]): dict.erase(key) removed += 1 return removed