Как отсортировать список студенческих записей по категориям в Python - PullRequest
2 голосов
/ 19 июня 2020

Предположим, у меня есть вложенный список, который выглядит следующим образом:

# Student records
data_list=[ # person, subject, grade
   ["John", "Physics", 5], ["John", "PC", 7], ["John", "Math", 8], 
   ["Mary", "Physics", 6], ["Mary", "PC", 10], ["Mary", "Algebra", 7], 
   ["Helen", "Physics", 7], ["Helen","PC", 6], ["Helen", "Algebra", 8], 
   ["Helen", "Analysis", 10], ["Bill", "PC", 10], ["Bill", "Analysis", 6], 
   ["Bill", "Math", 8], ["Bill", "Biology", 6], ["Michael", "Analysis", 10]
]

Как я могу создать код, который печатает, какой предмет посещал каждый студент? Вывод кода должен выглядеть так:

# Subjects taken by person
[["John", "Physics", "PC", "Math"],
["Mary", "Physics", "PC", "Algebra"],
...]

Я бы предпочел решение, которое использует только списки Python.

Ответы [ 3 ]

0 голосов
/ 19 июня 2020

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

from collections import defaultdict

subjects = defaultdict(list)
for record in data_list: 
    subjects[record[0]].append(record[1])
# subjects
defaultdict(list,
            {'John': ['Physics', 'PC', 'Math'],
             'Mary': ['Physics', 'PC', 'Algebra'],
             'Helen': ['Physics', 'PC', 'Algebra', 'Analysis'],
             'Bill': ['PC', 'Analysis', 'Math', 'Biology'],
             'Michael': ['Analysis']})

Затем его можно преобразовать в список списков:

subjects_list = [[x] + y for x, y in subjects.items()]
# subjects_list
[['John', 'Physics', 'PC', 'Math'],
 ['Mary', 'Physics', 'PC', 'Algebra'],
 ['Helen', 'Physics', 'PC', 'Algebra', 'Analysis'],
 ['Bill', 'PC', 'Analysis', 'Math', 'Biology'],
 ['Michael', 'Analysis']]

EDIT По запросу OP, вот решение, использующее только списки:

subject_list = []  # output
persons = []       # track unique persons
for record in data_list:
    if record[0] not in persons:
        persons.append(record[0])           # Track new person
        subject_list.append([record[0]])    # Add new person to output
        subject_list[-1].append(record[1])  # Add subject for person
    else:
        subject_list[persons.index(record[0])].append(record[1])
# subject_list
[['John', 'Physics', 'PC', 'Math'],
 ['Mary', 'Physics', 'PC', 'Algebra'],
 ['Helen', 'Physics', 'PC', 'Algebra', 'Analysis'],
 ['Bill', 'PC', 'Analysis', 'Math', 'Biology'],
 ['Michael', 'Analysis']]

EDIT 2 Вы можете обобщить этот подход, чтобы отсортировать ваши data_list по любому индексу (например, человек, ...), отфильтровывая категорию (например, предмет, оценка, ...)

def groupby(data, index, category):
    """Sort list of records by index and category
    """
    output = []
    indices = []
    for record in data:
        if record[index] not in indices:
            indices.append(record[index])
            output.append([record[index]])
            output[-1].append(record[category])
        else:
            output[indices.index(record[index])].append(record[category])
    return output

Это позволит вы можете перечислить предметы для каждого человека следующим образом:

# index 0 -> person
# category 1 -> subject
subject_list = groupby(data_list, 0, 1)

Или вы можете указать оценки на человека следующим образом:

# index 0 -> person
# category 2 -> grade
grade_list = groupby(data_list, 0, 2)
# grad_list
[['John', 5, 7, 8],
 ['Mary', 6, 10, 7],
 ['Helen', 7, 6, 8, 10],
 ['Bill', 10, 6, 8, 6],
 ['Michael', 10]]

Затем вы можете получить количество предметов, взятых на каждого человека. человек или средняя оценка, например:

import statistics

subjects_taken = [len(x) - 1 for x in subject_list]
average_grade = [statistics.mean(x[1:]) for x in grade_list]

Если сложить все вместе, вы получите:

persons = [x[0] for x in subject_list]
final_list = list(zip(persons, subjects_taken, average_grade))

# final_list
[('John', 3, 6.666666666666667),
 ('Mary', 3, 7.666666666666667),
 ('Helen', 4, 7.75),
 ('Bill', 4, 7.5),
 ('Michael', 1, 10)]
0 голосов
/ 19 июня 2020

Вот функция, которую вы можете попробовать:

def consolidate(data):
    # list of names from  data_list
    names = list(set([i[0] for i in data])) 
    consolidated = [] # empty list to get the sublists

    # Looping for each name
    for name in names:
        subList = [name] # sublist for each name
        for i in data: # loop for each item within data_list
            if i[0] == name: # if name is the same, append the subject
                subList.append(i[1])
        consolidated.append(subList) # append sublists in consolidated list
    return consolidated

Функция вызова:

consolidate(data_list)

Вывод:

[['Mary', 'Physics', 'PC', 'Algebra'], ['Helen', 'Physics', 'PC', 'Algebra', 'Analysis'],
['John', 'Physics', 'PC', 'Math'], ['Bill', 'PC', 'Analysis', 'Math', 'Biology'],
['Michael', 'Analysis']]
0 голосов
/ 19 июня 2020

Вы могли бы написать функцию, которая принимает вложенный список. Затем для каждого внутреннего списка вы можете инициализировать другой список из подсписок, если это уникальный человек, и в обоих случаях добавить новую тему в список этого человека. Отфильтруйте оценки и бей. При необходимости распечатайте

...