Python создает список списков, где первый элемент имеет длину один, а второй элемент имеет длину n? - PullRequest
0 голосов
/ 17 сентября 2018

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

fruitlist = [('Vendor A', 'Apples'),
('Vendor B', 'Apples'),
('Vendor C', 'Bananas'),
('Vendor A', 'Grapes'),
('Vendor A', 'Bananas'),
('Vendor B', 'Oranges')]

Что я хочу сделать, так это создать список: [[Vendor A, (Apples, Grapes, Bananas)], [Vendor B, (Apples, Oranges)], [Vendor C, (Bananas)]]

Итак, в основном, Продавец, а затем и их предложения. Это код, который у меня есть в настоящее время, он в основном проходит и вытаскивает просто список поставщиков, затем перебирает и фиксирует каждое предложение, однако вывод не совсем мне нужен.

vendors = list(set([x[0] for x in fruitlist]))
# this creates a list of just vendors:
output = [[] for x in range (len(vendors))]
#This creates a list with 3 empty lists inside (one for each vendor) where my output will be housed
    for x in range(0,len(vendors)):
        for y in range(0,len(fruitlist)):
            if fruitlist[y][0] == vendors[x]:
                output[x].append(fruitlist[y][1])

Вывод выглядит примерно так:

[['Apples', 'Oranges'], ['Apples', 'Grapes', 'Bananas'], ['Bananas']]

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

output[x].append((fruitlist[y][0],fruitlist[y][1]))

повторяет название продавца для каждого фрукта. Если я использую метод вставки, создается впечатление, что он создает новый элемент и увеличивает длину списка. Я пробовал несколько вещей, я пытался погуглить, но я не могу найти правильную формулировку. Если бы кто-нибудь мог указать мне правильное направление, я был бы очень благодарен.

Также кто-нибудь может объяснить, почему, когда я ищу поставщиков:

 ['Vendor B', 'Vendor A', 'Vendor C']

Это ставит "B" перед "A"? В моем первоначальном списке А был первый, назначает ли функция set случайный порядок?

Ответы [ 3 ]

0 голосов
/ 17 сентября 2018

( смотри ма, без словарей )

Данные

In [15]: fruitlist = [('Vendor A', 'Apples'),
    ...:              ('Vendor B', 'Apples'),
    ...:              ('Vendor C', 'Bananas'),
    ...:              ('Vendor A', 'Grapes'),
    ...:              ('Vendor A', 'Bananas'),
    ...:              ('Vendor B', 'Oranges')]

Выходной список, изначально пустой

In [16]: output = []

Мы собираемся использовать необычную возможность цикла for Python, то есть предложение else. Тело предложения else выполняется, если тело for завершилось нормально, то есть без break

In [17]: for vendor, fruit in fruitlist:
    ...:     for sublist in output:
    ...:         if sublist[0] == vendor:
    ...:             sublist[1].append(fruit)
    ...:             break
    ...:     else:
    ...:         output.append([vendor, [fruit]])

В конце концов мы проверяем наш результат

In [18]: output
Out[18]: 
[['Vendor A', ['Apples', 'Grapes', 'Bananas']],
 ['Vendor B', ['Apples', 'Oranges']],
 ['Vendor C', ['Bananas']]]

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

0 голосов
/ 17 сентября 2018

Вы можете использовать простой цикл for и dictionary не нужно его слишком усложнять

fruits = [ 
    ('Vendor A', 'Apples'),
    ('Vendor B', 'Apples'),
    ('Vendor C', 'Bananas'),
    ('Vendor A', 'Grapes'),
    ('Vendor A', 'Bananas'),
    ('Vendor B', 'Oranges')
]

dicta = {}

for vendor, item in fruits:
    if vendor not in dicta:
        dicta[vendor] = [item]
    else:
        dicta[vendor].append(item)

print(dicta)
(xenial)vash@localhost:~/python/stack_overflow$ python3.7 fruits.py
{'Vendor A': ['Apples', 'Grapes', 'Bananas'], 'Vendor B': ['Apples', 'Oranges'], 'Vendor C': ['Bananas']}
0 голосов
/ 17 сентября 2018

Наборы - это просто наборы элементов, порядок не такой, как у списков.

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

fruitlist = [('Vendor A', 'Apples'),
('Vendor B', 'Apples'),
('Vendor C', 'Bananas'),
('Vendor A', 'Grapes'),
('Vendor A', 'Bananas'),
('Vendor B', 'Oranges')]
vendors = {}
for vendor, fruit in fruitlist:
    vendors.setdefault(vendor, []).append(fruit)
ordered_fruitlist_vendors = [t[0] for t in fruitlist]
vendors_list = [[k, tuple(v)] for k,v in vendors.items()]
vendors_list.sort(key=lambda t: ordered_fruitlist_vendors.index(t[0]))

, что дает vendors_list как:

[['Vendor A', ('Apples', 'Grapes', 'Bananas')], ['Vendor B', ('Apples', 'Oranges')], ['Vendor C', ('Bananas',)]]

Однако я сомневаюсь, что преобразование аккуратного словаря в этот неуклюжий список из двухэлементных списков с кортежами необходимо. Конечно, вы хотите иметь возможность получить фрукты у продавца за O(1) время с vendors['Vendor A'] вместо того, чтобы перебирать этот список, который будет O(n)? В любом случае, оба метода теперь являются опциями!


Объяснение setdefault.

Метод setdefault словаря принимает два параметра - ключ и значение. Если ключ уже присутствует в словаре, возвращается текущее значение, в противном случае ключ создается со значением, переданным в функцию, и возвращается это значение.

Например:

>>> d = {1:2}
>>> d.setdefault(1,3)
2
>>> d
{1: 2}
>>> d.setdefault(3,4)
4
>>> d
{1: 2, 3: 4}

Итак, хитрый трюк, использующий этот метод, - установить ключ в пустой список ([]). Тогда, если у нас еще нет этого ключа (в нашем случае этот поставщик еще не был замечен), тогда возвращается пустой список. В противном случае мы получаем ссылку на список, который содержит все плоды этого вендора, которые мы видели до сих пор. Прелесть в том, что мы можем просто добавить наш новый фрукт в независимо от того, возвращается ли , и либо будет создана новая запись для этого поставщика, и добавлен новый фрукт, либо, если этот продавец уже существует, мы просто добавим ранее созданный список.

Это означает, что нам нужно перебирать fruitlist только один раз, чтобы решение было эффективным.


Еще один пример метода в действии со списками:

>>> d = {}
>>> d.setdefault(1, []).append(2)
>>> d
{1: [2]}
>>> d.setdefault(1, []).append(3)
>>> d.setdefault(1, []).append(4)
>>> d
{1: [2, 3, 4]}
>>> d.setdefault(2, []).append(3)
>>> d.setdefault(2, []).append(3)
>>> d.setdefault(2, []).append(3)
>>> d
{1: [2, 3, 4], 2: [3, 3, 3]}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...