# How to get random object with given property from array of objects?

Attention Topic was automatically imported from the old Question2Answer platform.

I have an array of objects. Each object can have properties. I need a take a random element of filtered array by some condition. For i.e. random element with top priority. The problem that I don’t know what priority is top, so I can’t just go through array and make new array with that priority. Or condition can be more complicated (for i.e. random object with health more 50 and closer to player than 100)

Here is my variant of solution of this problem:

``````extends Node

var arr = ["Tst1", "Tst2", "Tst3", "Test4", "Test5", "t1", "t2", "tt1", "tt2"]
var dict_arr = [{"value": 50}, {"value": 100, "name": "test1"}, {"value": 100, "name": "test2"}, {"value": 20}, {"value": 110, "name": "test3"}, {"value": 110, "name": "test4"}, {"value": 110, "name": "test5"}]

randomize()
print(random_element(arr))
print(random_element_with_biggest_property(dict_arr, "value"))
print(random_element_with_condition(arr, funcref(self, "lengthBigger2")))
print(random_element_with_condition(arr, funcref(self, "lengthBigger3")))
print(random_element_with_condition(arr, funcref(self, "lengthBigger4")))

func random_element(array):
return array[randi() % array.size()]

func random_element_with_biggest_property(array, property : String):
if array.empty():
return null

var accepted = []
var biggestValue = array[0].get(property) if property in array[0] else null

for element in array:
if property in element:
var value = element.get(property)

if value > biggestValue:
accepted.clear()
biggestValue = value
accepted.append(element)
elif value == biggestValue:
accepted.append(element)

if accepted.empty():
return null
else:
return random_element(accepted)

func random_element_with_condition(array, conditionalFunc : FuncRef):
if array.empty():
return null

var accepted = []

for element in array:
if conditionalFunc.is_valid() and conditionalFunc.call_func(element):
accepted.append(element)

if accepted.empty():
return null
else:
return random_element(accepted)

func lengthBigger2(element):
return element.length() > 2

func lengthBigger3(element):
return element.length() > 3

func lengthBigger4(element):
return element.length() > 4
``````

Can you review it? What problems does it have? What is about performance?

Is it possible to find more elegant solution?

I’m a little confused, in your question you call them objects with properties, but here they seem to be string literals with loosely associated values in a dictionary (the string literals in your dictionary do not exactly match your capitalization in your array, and the first item in your dictionary has no “name” key).
When I read your question I expected custom objects with member variables as properties, which is probably how I would do it. Do these objects have representation in your game beyond “test” (are they monsters, players, items, etc)? The solution you’ve got now adds a convoluted (IMO) layer of abstraction that divorces the original data from how you want to manipulate it. In other words, those dictionaries have to be populated somehow, and you may introduce bugs in the transcription process that can be difficult to diagnose. If you instead used an array of references to objects in memory, potentially with a custom class (declared at the top of the object’s script with the `class_name` keyword in GDScript), you could construct a `for` loop to iterate over the collection, creating another collection of references based on some condition, and then randomly choosing out of that second collection.
A hypothetical example using custom objects with `class_name` keyword and `for` loop member variable checking (not a complete implementation of what you want, but hopefully will get you there):
Class1.gd:

``````extends Object

class_name Class1

var foo = 20
var bar = "spam"
``````

Class2.gd:

``````extends Object

class_name Class2

var foo = 20
var baz = "runcible"
``````

debug_scene.gd:

``````extends Node2D

var collection = []

for i in 10:
var object1 = Class1.new()
var object2 = Class2.new()
collection.push_back(object1)
collection.push_back(object2)

for item in collection:
print("item number", collection.find(item))
if "foo" in item:
print("item has member variable foo")
if "bar" in item:
print("item has member variable bar")
if "baz" in item:
print("item has member variable baz")
``````

output:

``````item number0
item has member variable foo
item has member variable bar
item number1
item has member variable foo
item has member variable baz
item number2
item has member variable foo
item has member variable bar
item number3
item has member variable foo
item has member variable baz
...
``````

DDoop | 2020-08-06 16:48

in your question you call them objects with properties, but here they
seem to be string literals with loosely associated values in a
dictionary

it will be scene nodes and gdscript objects in the real game. I guess, that interface the same as with the dictionaries

Robotex | 2020-08-06 17:04