Как ускорить замену элементов в списке Python?

Есть список mapping_pixels=[(68, 68, 125, 255), (68, 68, 125, 255), (71, 72, 86, 255), .....] в котором 1280*1280 элементов и есть список unique_pixels[] из множества уникальных элементов списка mapping_pixels[], коих 3800 шт. Надо все элементы списка mapping_pixels[] заменить на индекс элементов списка unique_pixels[], если значения совпадают. Я сделал две итерации и сравниваю по элементу, но это очень долго. Подскажите способ что бы процесс не занимал много времени.

from PIL import Image

def create_map2():
    im = Image.open('sprite/map3.png').convert('RGBA')
    mapping_pixels = list(im.getdata())
    mapping = []
    row = []
    unique_pixels = list(set(list(mapping_pixels)))
    step = 0
    unique_pixels_dict = {
        value: i
        for i, value in enumerate(unique_pixel)
    }
    for pixel in mapping_pixel:
        if len(row) == im.width:
            mapping.append(row)
            row = []
        row.append(unique_pixels_dict[pixel])
    return im.width, im.height, list(set(list(im.getdata()))), mapping

map2 = create_map2()

Map


Ответы (2 шт):

Автор решения: AivanF.

Сударь, вам надо учиться задавать понятные вопросы :)

  1. "тот же самый список b[] без повторения элементов в нём 3800 элементов" – это скорее не тот же самый, а "список b из множества уникальных элементов списка a, коих 3800 шт".
  2. Чтобы упростить жизнь отвечающим, стоит связать вашу абстрактную формулировку вопроса с кодом, а не вынуждать перечитывать вопрос пару раз: список a в коде это map_pixel, а b это l.
  3. l плохое название, я бы заменил на что-то более осмысленное вроде unique_values.
  4. Насчёт плохой практики использования встроенных значений вроде map как имён переменных вам уже подсказали.

Проблема же здесь в том, что из-за вложенности циклов сложность алгоритма выходит квадратичной, что легко решается использованием словаря с маппингом значений из списка b в их индексы:

map_pixels = list(...)
unique_values = list(set(map_pixels))
unique_values_indices = {
    value: i
    for i, value in enumerate(unique_values)
}

row = []
for pixel in map_pixels:
    row.append(unique_values_indices[pixel])

Кстати, "Special cases aren't special enough to break the rules", и ваш особый кейс с (68, 68, 122, 255) можно реализовать более грамотно:

first_values = [(68, 68, 122, 255)]
unique_values = first_values + list(set(map_pixels) - set(first_values))

Таким образом, это особое значение всегда будет иметь нулевой индекс, зато не потребует отдельной обработки в цикле, а при желании эту штуку легко масштабировать добавив в список first_values дополнительные первые значения.

Привет собрату гейм-девелоперу ?
→ Ссылка
Автор решения: lQS_Tolya

попробовал ускорить

from PIL import Image
import numpy as np

def create_map2():
    im = Image.open('sprite/map3.png').convert('RGBA')
    mapping_pixel = (list(im.getdata()))
    unique_pixel = (list(set(list(im.getdata()))))
    unique_pixel_dict = {
        value: i
        for i, value in enumerate(unique_pixel)
    }
    mapping = list(map(lambda x: unique_pixel_dict[x], mapping_pixel))
    mapping = np.array(mapping)
    mapping = self.mapping.reshape(im.height, im.width)

    return im.width, im.height, unique_pixel , mapping

map2 = create_map2()
→ Ссылка