Как найти конкретный словарь в списке словарей, используя ключевые сравнения

#python #list #dictionary

#python #Список #словарь

Вопрос:

У меня есть список задач, которые содержат task1 и task2 . Я не хочу добавлять, task3 если record_id of task3 соответствует существующим задачам. Короче говоря, если record_id из 2 элементов в списке tasks имеют одинаковые значения, задача считается одинаковой.

 task1 = {
        'record_id': '1,2,3',
        'location': 'l1',
        'instruction_parameters': {
            'NAME': 'project_name1'
        },
        'marked_points': 'marked_points1',
        'marked_polygons': 'marked_polygons1',
    }
task2 = {
        'record_id': '8,7,3',
        'location': 'l2',
        'instruction_parameters': {
            'NAME': 'project_name2'
        },
        'marked_points': 'marked_points2',
        'marked_polygons': 'marked_polygons2',
    }

tasks = [task1, task2]

task3 = {
        'record_id': '3,1,2',
        'location': '',
        'instruction_parameters': {
            'NAME': 'project_name3'
        },
        'marked_points': 'marked_points3',
        'marked_polygons': 'marked_polygons3',
    }

task3_record_ids = task3['record_id'].split(',')
  

Я попробовал следующий подход, но первый выдал мне StopIteration ошибку, а второй ничего не вернул.

 previous_dup_task_dict = next(item for item in tasks if set(item['record_id'].split(',')) == set(task3_record_ids))
  

Второй подход :

 previous_dup_task_dict = filter(lambda task: set(task['record_id'].split(',')) == set(record_ids), tasks)
  

Обратите внимание, что порядок record_id s не имеет значения, поэтому в этом случае task3 должны совпадать task1 , поскольку их record_id s имеют одинаковые значения, хотя и в разном порядке, что приемлемо.

Комментарии:

1. I don't want to append task 3 if one of the keys of task3 matches the existing tasks. Могут ли две задачи быть помечены как идентичные, если record_id содержат одинаковое значение? Можете ли вы уточнить?

2. @arsho извините, пожалуйста, посмотрите мои правки. Только если record_id совпадает, то 2 задачи считаются идентичными.

Ответ №1:

вы должны сравнить все задачи в списке с task3 таким образом:

 task1 = {
    'record_id': '1,2,3',
    'location': 'l1',
    'instruction_parameters': {
        'NAME': 'project_name1'
    },
    'marked_points': 'marked_points1',
    'marked_polygons': 'marked_polygons1',
}
task2 = {
    'record_id': '8,7,3',
    'location': 'l2',
    'instruction_parameters': {
        'NAME': 'project_name2'
    },
    'marked_points': 'marked_points2',
    'marked_polygons': 'marked_polygons2',
}

tasks = [task1, task2]

task3 = {
    'record_id': '3,1,2',
    'location': '',
    'instruction_parameters': {
        'NAME': 'project_name3'
    },
    'marked_points': 'marked_points3',
    'marked_polygons': 'marked_polygons3',
}

match = False
for task in tasks: 
    if set(task3["record_id"].split(",")) == set(task["record_id"].split(",")): #set for ignoring order of list items
        match = True

if not match:
    tasks.append(task3)

print(tasks)
  

вы должны использовать set для сравнения двух списков без учета индекса элементов списка.

Ответ №2:

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

Ответ №3:

Попробуйте это :

 task1 = ...
task2 = ...
task3 = ...
tasks = [task1, task2]
match_found = False
for task in tasks:
    if sorted(task1['record_id'].split(',')) == sorted(task3['record_id'].split(',')):
        match_found = True
    else: 
        continue

if match_found == False:
    tasks.append(task3)
  

Сначала назначьте переменную для проверки, присутствует ли в списке какой-либо элемент с таким же record_id ключом tasks . Теперь пройдитесь по tasks списку и разделите каждый элемент record_id на , , отсортируйте их и сравните с tasks3 . Если они совпадают, присвойте этой переменной значение True . Теперь, если переменная является, True затем добавьте task3 в tasks список.

Ответ №4:

Одним из решений является использование класса в качестве оболочки. Этот класс может наследоваться list .

 import json


task1 = {
        'record_id': '1,2,3',
        'location': 'l1',
        'instruction_parameters': {
            'NAME': 'project_name1'
        },
        'marked_points': 'marked_points1',
        'marked_polygons': 'marked_polygons1',
}

task2 = {
    'record_id': '8,7,3',
    'location': 'l2',
    'instruction_parameters': {
        'NAME': 'project_name2'
    },
    'marked_points': 'marked_points2',
    'marked_polygons': 'marked_polygons2',
}

task3 = {
    'record_id': '3,1,2',
    'location': '',
    'instruction_parameters': {
        'NAME': 'project_name3'
    },
    'marked_points': 'marked_points3',
    'marked_polygons': 'marked_polygons3',
}


class Tasks(list):
    def get_identifier(self, s):
        s = s.replace(" ","")
        return sorted(list(map(int, s.split(","))))

    def compare_tasks(self, first_task, second_task):
        if self.get_identifier(first_task['record_id']) == self.get_identifier(second_task['record_id']):
            return True
        return False

    def append(self, new_task):
        task_exist = False
        for task in self:
            if self.compare_tasks(task, new_task):
                task_exist = True
                #raise ValueError('Task already in list: {}'.format(new_task))
        if task_exist == False:
            super().append(new_task)

tasks = Tasks()
tasks.append(task1)
tasks.append(task2)
tasks.append(task3)
print(json.dumps(tasks, indent = 4))
  

Вывод:

 [
    {
        "location": "l1",
        "marked_points": "marked_points1",
        "instruction_parameters": {
            "NAME": "project_name1"
        },
        "record_id": "1,2,3",
        "marked_polygons": "marked_polygons1"
    },
    {
        "location": "l2",
        "marked_points": "marked_points2",
        "instruction_parameters": {
            "NAME": "project_name2"
        },
        "record_id": "8,7,3",
        "marked_polygons": "marked_polygons2"
    }
]
  

Вы можете вызвать ValueError для добавления дублирующейся задачи в tasks .

Для повышения ValueError раскомментируйте следующий комментарий:

#raise ValueError('Task already in list: {}'.format(new_task))

Пояснения:

  • Tasks наследуется list .
  • Каждая задача имеет уникальный идентификатор: отсортированный список record_id ключей.
  • Две задачи идентичны, если у них одинаковый уникальный идентификатор.
  • json.dumps используется для отображения списка с правильным отступом.