Python создает вложенные списки из CSV - PullRequest
1 голос
/ 10 июня 2019

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

list1 = [[(0, 0), (0, 1), (0, 2)],
         [(1, 0), (1, 1), (1, 2)],
         [(2, 0), (3, 1), (3, 2)]]

Чтобы я мог получить доступ к элементам

list1[0] = [(0, 1), (0, 2),(0, 3)]    # type list

list1[0][0] = (0,1)    # type tuple

list1[0][0][0] = 0    #type int

У меня есть целые числана CSV-файл, который я могу манипулировать, как я хочу.Никакого конкретного формата не требуется. Сейчас данные находятся в шести столбцах без пробелов или в шести целых числах на строку

Я пробовал этот код, но он не работал так, как я хотел:

import csv

with open('file1.csv', 'r') as f:
  reader = csv.reader(f)
  list1 = list(reader)

print(list1)

Ответы [ 2 ]

0 голосов
/ 10 июня 2019

Проблема здесь в том, что ваша структура является трехмерной, но CSV-файлы лучше всего подходят для двумерных данных.Существует вторичная проблема, заключающаяся в том, что ваш внутренний уровень состоит из кортежей, но внешние уровни представляют собой списки.

Вы можете решить обе эти проблемы, рассматривая это как простой список списков общих объектов Python (т. Е.игнорируя тот факт, что кортежи определяют 3-е измерение).Затем вы можете использовать код, подобный следующему:

import csv, ast
# store some sample data
list1 = [[(0, 0), (0, 1), (0, 2)],
         [(1, 0), (1, 1), (1, 2)],
         [(2, 0), (3, 1), (3, 2)]]

with open('file1.csv', 'w') as f:
    w = csv.writer(f)
    w.writerows(list1)

# read the sample data
with open('file1.csv', 'r') as f:
    r = csv.reader(f)
    list2 = [
        [ast.literal_eval(t) for t in row]
        for row in r
    ]

list2 == list1
# True

Обратите внимание, что самые внутренние объекты будут храниться как строковое представление кортежа.Затем, когда они считываются обратно, ast.literal_eval преобразует их обратно в кортежи.

В качестве альтернативы, я бы настоятельно рекомендовал нормализовать представление данных, например, хранить одну (x, y) пару в каждой строке файла CSV.вместе с их координатами строки и столбца.Это можно сделать следующим образом:

import csv

# store some sample data
list1 = [[(0, 0), (0, 1), (0, 2)],
         [(1, 0), (1, 1), (1, 2)],
         [(2, 0), (3, 1), (3, 2)]]

with open('file1.csv', 'w') as f:
    w = csv.writer(f)
    for i, row in enumerate(list1):
        for j, (x, y) in enumerate(row):
            w.writerow([i, j, x, y])

# read the sample data
with open('file1.csv', 'r') as f:
    r = csv.reader(f)
    raw_data = [[int(v) for v in row] for row in r]

# figure out how many rows and columns there are
height = max(i for i, j, x, y in raw_data) + 1
width = max(j for i, j, x, y in raw_data) + 1
# create an empty "array" of the right size
list2 = [[None] * width for r in range(height)]
# fill up the array
for i, j, x, y in raw_data:
    list2[i][j] = (x, y)

list2 == list1
# True

В качестве другой альтернативы: звучит так, как будто у вас есть свободный выбор структуры файла, поскольку вам не нужно организовывать свой CSV каким-либо конкретным способом.В этом случае вам лучше использовать бинарный или json-файл вместо csv, поскольку csv плохо подходит для хранения структурированных переменных, подобных вашей.

pickle намного проще, но создает двоичный файл:

import pickle

# store some sample data
list1 = [[(0, 0), (0, 1), (0, 2)],
         [(1, 0), (1, 1), (1, 2)],
         [(2, 0), (3, 1), (3, 2)]]

with open('file1.p', 'wb') as f:
    pickle.dump(list1, f)

# read the data back
with open('file1.p', 'rb') as f:
    list2 = pickle.load(f)

list1 == list2
# True

json создает более читаемый файл, но код выглядит сложнее.

import json

# store some sample data
list1 = [[(0, 0), (0, 1), (0, 2)],
         [(1, 0), (1, 1), (1, 2)],
         [(2, 0), (3, 1), (3, 2)]]

with open('file1.json', 'w') as f:
    json.dump(list1, f)

# read the data back
with open('file1.json', 'r') as f:
    list2 = json.load(f)
    # convert inner lists to tuples (json doesn't distinguish them)
    list2 = [[tuple(t) for t in row] for row in list2]

list1 == list2
# True
0 голосов
/ 10 июня 2019

Вам придется проделать немного больше работы, чтобы отформатировать список так, как вы хотите.

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

import csv

list1 = []
with open('file1.csv', 'r') as f:
    reader = csv.reader(f)
    for line in reader:
        # split line into pairs of integers
        pairs = [(int(i), int(j)) for i, j 
                 in zip(line[0::2], line[1::2])]
        list1.append(pairs)

Редактировать:

@ gregorio-pedullà запросил объяснение индексации, используемой в строке

pairs = [(int(i), int(j)) for i, j 
         in zip(line[0::2], line[1::2])]

При нарезке последовательностей в Python синтаксис имеет вид sequence[start:stop:step].Если вы пропустите stop, то срез автоматически остановится в конце последовательности.

Так что line[0::2] означает «начать с первого элемента (индекс 0) и брать каждый второй элемент до концасписок."Проще говоря, это извлечет все элементы с четными индексами.

Аналогично, line[1::2] означает «начать со второго элемента и брать каждый второй элемент до конца списка».Это извлечет все элементы с нечетными индексами.

Если вы хотите поэкспериментировать с примером, запустите:

example_list = [0, 1, 2, 3, 4, 5]

evens = example_list[0::2]
print(evens)
# [0, 2, 4]

odds = example_list[1::2]
print(odds)
# [1, 3, 5]

print(zip(evens, odds))
# [(0, 1), (2, 3), (4, 5)]

В вашем случае вы хотели извлечь пары целых чисел изкаждая строка.Одним из самых простых способов создания пар последовательных элементов в списке является нарезка элементов с четным индексом и элементов с нечетным индексом, а затем zip их.

...