簡體   English   中英

根據特定屬性對對象列表進行排序(或部分排序)

[英]Sorting (or partially sorting) a list of objects based on a specific attribute

問題

我有一個對象列表。 每個 object 都有兩個屬性: “score”“coordinates” 我需要根據score屬性找到列表中最大的N個對象。 我遇到的主要問題是使用score屬性對對象進行排序。 排序可以是部分的。 我只對N個最大的對象感興趣。

當前解決方案

我目前的方法不是最優雅也不是最有效的。 這個想法是創建一個包含 object indices及其scoredictionary ,然后對分數列表進行排序並使用dictionary來索引產生最大分數的對象。

這些是步驟:

  1. 創建一個scores列表。 列表的每個元素對應一個 object。 即第一個條目是第一個object的分數,第二個條目是第二個object的分數,以此類推。

  2. 使用對象的scores作為key創建dictionary ,使用 object index作為value

  3. 使用heapq對分數列表進行排序以獲得N個最大的對象。

  4. 使用dictionary來獲取那些scores最高的對象。

  5. 創建一個僅包含N個最大得分對象的新list

代碼片段

這是我的排序 function:

import random
import heapq


# Gets the N objects with the largest score:
def getLargest(N, objects):
    # Set output objects:
    outobjects = objects

    # Get the total of objects in list:
    totalobjects = len(objects)

    # Check if the total number of objects is bigger than the N requested
    # largest objects:

    if totalobjects > N:

        # Get the "score" attributes from all the objects:
        objectScores = [o.score for o in objects]

        # Create a dictionary with the index of the objects and their score.
        # I'm using a dictionary to keep track of the largest scores and
        # the objects that produced them:
        objectIndices = range(totalobjects)
        objectDictionary = dict(zip(objectIndices, objectScores))

        # Get the N largest objects based on score:
        largestObjects = heapq.nlargest(N, objectScores)
        print(largestObjects)

        # Prepare the output list of objects:
        outobjects = [None] * N

        # Look for those objects that produced the
        # largest score:
        for k in range(N):
            # Get current largest object:
            currentLargest = largestObjects[k]
            # Get its original position on the keypoint list:
            position = objectScores.index(currentLargest)
            # Index the corresponding keypoint and store it
            # in the output list:
            outobjects[k] = objects[position]

    # Done:
    return outobjects

此代碼段生成100隨機對象,用於測試我的方法。 最后一個循環打印N = 3隨機生成的具有最大score的對象:

# Create a list with random objects:
totalObjects = 100
randomObjects = []


# Test object class:
class Object(object):
    pass


# Generate a list of random objects
for i in range(totalObjects):
    # Instance of objects:
    tempObject = Object()
    # Set the object's random score
    random.seed()
    tempObject.score = random.random()
    # Set the object's random coordinates:
    tempObject.coordinates = (random.randint(0, 5), random.randint(0, 5))
    # Store object into list:
    randomObjects.append(tempObject)

# Get the 3 largest objects sorted by score:
totalLargestObjects = 3
largestObjects = getLargest(totalLargestObjects, randomObjects)

# Print the filtered objects:
for i in range(len(largestObjects)):
    # Get the current object in the list:
    currentObject = largestObjects[i]
    # Get its score:
    currentScore = currentObject.score
    # Get its coordinates as a tuple (x,y)
    currentCoordinates = currentObject.coordinates
    # Print the info:
    print("object: " + str(i) + " score: " + str(currentScore) + " x: " + str(
        currentCoordinates[0]) + " y: " + str(currentCoordinates[1]))

我目前的方法可以完成工作,但必須有一種更Pythonic (更矢量化)的方式來實現相同的目標。 我的背景主要是C++,我還在學習Python。 歡迎任何反饋。

附加信息

最初,我在尋找類似於 C++ 的std:: nth_element的東西。 NumPy 的partition在 Python 中似乎提供了這個功能。 不幸的是,雖然std::nth_element支持用於自定義排序的謂詞,但 NumPy 的partition不支持。 我最終使用了heapq ,它可以很好地完成工作並按所需順序排序,但我不知道基於一個屬性進行排序的最佳方式。

元組是你需要的。 不是將分數存儲在堆中,而是將(score, object)的元組存儲在堆中。 它將嘗試按分數進行比較並返回一個元組列表,您可以使用它來檢索原始對象。 這將節省您通過分數檢索對象的額外步驟:

heapq.nlargest(3, ((obj.score, obj) for obj in randomObjects))
# [(0.9996643881256989, <__main__.Object object at 0x155f730>), (0.9991398955041872, <__main__.Object object at 0x119e928>), (0.9858047551444177, <__main__.Object object at 0x15e38c0>)]

對於現實世界的示例: https://akuiper.com/console/g6YuNa_1WClp

或者正如@shriakhilc 評論的那樣,使用heapq.nlargest中的key參數來指定您要按分數進行比較:

heapq.nlargest(3, randomObjects, lambda o: o.score)

我建議你使用排序的 python 原生方法 + lambda function。 見這里: https://docs.python.org/3/howto/sorting.html#sortinghowto

基本上,這是您可以擁有的:

myList = [
  {score: 32, coordinates: [...]},
  {score: 12, coordinates: [...]},
  {score: 20, coordinates: [...]},
  {score: 8, coordinates: [...]},
  {score: 40, coordinates: [...]},
]

# Sort by score DESCENDING
mySortedList = sorted(myList, key=lambda element: element['score'], reverse=True)

# Retrieve top 3 results
myTopResults = mySortedList[0:3]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM