Build sorted list from list?

I have a list

“DistanceList” = [10,20,5,1]

and

hooks list = [hook1, hook2, hook3, hook4]

how would I sort list 1, and list 2 using the same sorting as list 1?

[hook4, hook3, hook1, hook2]
[1, 5, 10, 20]

This is for a dynamic light manager for resources.

You need two lists ? Maybe you can use a dictionary?
DistanceList = { 10:“hook”, 20:“hook2”, 5:“hook3”, 1:“hook4” }

DistanceList[5] >> ‘hook3’

so the idea here, is build 3 lists,
Lights,
Hooks,
Distances,

and run checks every so often, and shuffle the lights to the closest hooks,

a dictionary would work, as if one item is sorted so is the other?

import bge




def main():


    cont = bge.logic.getCurrentController()
    own = cont.owner
    lights = []
    hooks=[]
    Dlist=[]
    scene=bge.logic.getCurrentScene()
    if 'Lights' not in own:
        own['Cam']=scene.objects['Camera']
        for objects in scene.objects:
            if 'Lights' in objects:
                lights+=objects
               
            if 'Hook' in objects:
                hooks+=objects
                Dlist+=objects.getDistanceTo(own['Cam']])
                    
        own['Lights']=lights
        own['Hooks']=hooks
        own['DList']=Dlist
       
                
                                
    else:
        index=0
        for hooks in own['Hooks']:
            own['Dlist'][index]=hooks.getDistanceTo(own['Cam'])
            index+=1
        x=0    
        for light in own['Lights']:
            x+=1
       
        ##sort lists here
        index=0 


        for lights in own['LightList']:
            lights.worldPosition=own['Hooks'][index].worldPosition
            lights.worldOrientation=own['Hooks'][index].worldOrientation
            lights.setParent(own['Hooks'][index])
            index+=1
main()



The question is if you want to sort the same items just by different categories.

Btw. a dictionary typically is not sorted

How about you sort them as tuples.


student_tuples = [
        ('john', 'A', 15),
        ('jane', 'B', 12),
        ('dave', 'B', 10),
]
# sort by age [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
sorted(student_tuples, key=lambda student: student[2])   

Courtesy of https://wiki.python.org/moin/HowTo/Sorting

Also a dictionary is a much better approach than separate lists.
Hooks = { hook:{“d”:0,“someotherfeature”:[]}}
And sort it the same way with a key function.

I am resorting the list every x frames, so only the first 8 will be populated (as there are only 8 lights in light list)

I created this approach for my script (I don’t use bge but the idea is the same), I used classes instead because I wanted to access fields in a more meaningful way, plus that I wanted to provide support to sort items in more than 10 different fields. So using a tuple was not good for me.


import bge


list_distance = []
list_sorted = []


class DistanceData:
	def __init__(self, name, dist):
		self.name = name
		self.dist = dist


def print_distance_data_list(list):
	c = 0
	for i in list:
		print("%i. %s: %.2f" % (c, i.name, i.dist))
		c += 1


def main():
	scene = bge.logic.getCurrentScene()
	cube = scene.objects['Cube']


	keyboard = bge.logic.keyboard
	JUST_ACTIVATED = bge.logic.KX_INPUT_JUST_ACTIVATED


	if keyboard.events[bge.events.ONEKEY] == JUST_ACTIVATED:
		print("Building Distance List")
		global list_distance
		list_distance.clear()
		for i in scene.objects:
			if type(i) is bge.types.KX_LightObject:
				list_distance.append(DistanceData(i.name, i.getDistanceTo(cube)))
		print_distance_data_list(list_distance)


	if keyboard.events[bge.events.TWOKEY] == JUST_ACTIVATED:
		print("Sorting Based On Distance")
		sort = sorted(list_distance, key=lambda x: x.dist)
		print_distance_data_list(sort)


	if keyboard.events[bge.events.THREEKEY] == JUST_ACTIVATED:
		print("Sorting Based On Name")
		sort = sorted(list_distance, key=lambda x: x.name)
		print_distance_data_list(sort)



Notes: Instead of key presses you can use a time elapsed interval. Also instead of just printing the sorted list you can store it for caching.

Better to use named tuple if you’re not changing the data, and operator.attrgetter for longer lists

If you’re creating a light manager you’re going to have to recalculate the distances every time anyway as they will change as your camera moves.

The easiest way to sort a list is using a lambda key. It’s a kind of mini function, packed in to one line.

 sorted_list =sorted(list, key =lambda self,other=player:self.getDistanceTo(other))

(That’s untested as I’m writing this on my phone)

The light list doesn’t need to be sorted, only the light hooks do.

I have been rethinking, maybe I can just use a near sensor, and its sorted anyway?

Oh i edited my post after you replied.
I hate writing on my phone. :frowning:

Well both methods are important, does the near sensor take longer the more objects there are?

also, near does not appear to sort for distance, as I thought it would,

Why should it sort?

It just senses.

And yes more objects = more candidates = more to do.

With some clever assumptions a lot of calculations can be avoided. But I do not know how it is implemented. I know that the near sensor is heavy and it will not detect lights.

step 1 build a list of lights, we will say there are 4,

step 2 get a list of all light hooks

step 3 sort list, so 0 is closest

step 4 if there are 4 hooks, move lights to 4 closest hooks

yeah, but what do you do for,open world games at night?

I was planning on using an equation with
Distance is most importantant up close
angle is important further away.

camera.getVectTo(hook)-camera.worldOrientation.col[2]

Geo is making a kit to build a large city, and objects at far LOD will not have light hooks,
they will use emissive textures, however closer will have light hooks.

another thing, I have to somehow change what mesh is used during the night , so lights are off during the day…

the city will be powered down initially, but this is still a major concern.

well , others have written already all replies,
yes , sorted() , is decisely “THE TOOL” (is useful also in other 1000 cases)

what lack in this TD , is the mention of >>scene.lights<< !!!

maybe not solve all problems, but a good amount!
since you had a little list to iterate , not huge and wasting!
so , a lot of code or setup is avoidable thanks to it!

umh, in my opinion 2 lists are perfect,

there will always be the same lights, so there is no need to iterate,(lights)

the same 8 lights will be shuffled to the hooks,

but I need to write an equation that the first few lights are weighted heaviest by distance, and then the last lights are weighted most by angle.

so I will need to iterate the hook list, and sort it every x frames, then move the lights,

Sorted just does not look like regular python

what does

>>> mean?

Woa, :eek:.
Didn’t expect this. Heh :).

Download/look at python from https://www.python.org/
That is the regular python.
It has an interactive shell, which is like a command line where you can run python line by line.
It is only decoration, saying this is the line the user wrote.

Like, haven’t you looked up any python video tutorials before?

yes, the syntax is a bit strange,
it is a function that run internally a loop and want a function to iterate the items.
anyway if you try to make the same work with normal code , you see that is better “memorize” how work sorted() :yes:

supposing you want know the nearest enemy:

player = cont.owner
enemies = own[“enemies”]
enemies_sorted = sorted(enemies, key=player.getDistanceTo)

for performances reason better this (EDIT: thinking better probably is the same!)

player = cont.owner
enemies = own[“enemies”]
player_distance_func = player.getDistanceTo
enemies_sorted = sorted(enemies, key=player_distance_func)

using scene.lights basically you not need to the hooks
you can use lights inactive as hooks, then the lights real can replace some attribute.(not all)
he concept is the same, seem just more flexible :wink:

The “>>>” Symbols are not valid Python syntax. They’re the output visible in a Python interactive interpreter session when something is printed out.