Добавить символ и удалить последнюю запятую в файле JSON

Я пытаюсь создать файл JSON через CSV. Код ниже создает данные, но не совсем там, где я хочу. У меня есть некоторый опыт работы с питоном. Насколько я понимаю, файл JSON должен быть написан так [{}, {}, ..., {}].

Как мне?:

  1. Я могу вставить ",", но как удалить последний ","?

  2. Как мне вставить "[" в самом начале и "]" в самом конце? Я попытался вставить его в outputfile.write ('[' ... и т. д.), Он отображается слишком во многих местах.

  3. Не включать заголовок в первую строку файла json.

Names.csv:

id,team_name,team_members
123,Biology,"Ali Smith, Jon Doe"
234,Math,Jane Smith 
345,Statistics ,"Matt P, Albert Shaw"
456,Chemistry,"Andrew M, Matt Shaw, Ali Smith"
678,Physics,"Joe Doe, Jane Smith, Ali Smith "

Код:

import csv
import json
import os

with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    for line in infile:
         row = dict()
         # print(row)
         id, team_name, *team_members = line.split(',')
         row["id"] = id;
         row["team_name"] = team_name;
         row["team_members"] = team_members
         json.dump(row,outfile)
         outfile.write("," + "\n" )

Результат на данный момент:

{"id": "id", "team_name": "team_name", "team_members": ["team_members\n"]},
{"id": "123", "team_name": "Biology", "team_members": ["\"Ali Smith", " Jon Doe\"\n"]},
{"id": "234", "team_name": "Math", "team_members": ["Jane Smith \n"]},
{"id": "345", "team_name": "Statistics ", "team_members": ["\"Matt P", " Albert Shaw\"\n"]},
{"id": "456", "team_name": "Chemistry", "team_members": ["\"Andrew M", " Matt Shaw", " Ali Smith\"\n"]},
{"id": "678", "team_name": "Physics", "team_members": ["\"Joe Doe", " Jane Smith", " Ali Smith \""]},

С pandas это было бы очень просто ...

cs95 01.05.2018 17:56

Вы должны поместить эти словари в массив (в Python обычно называется списком). После этого вы выводите.

Anton vBR 01.05.2018 18:05

Вам нужен правильный массив JSON ([{}, {}, {}]) или поток объектов JSON ({} {} {}). Последовательность объектов, разделенных запятыми, недопустима.

chepner 01.05.2018 18:05

Что такое выход желанный? Должны ли члены команды быть разделены на свой собственный массив?

chepner 01.05.2018 18:16

@chepner Да, у членов команды должен быть свой список / массив, разделенный запятыми.

sharp 01.05.2018 18:49
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
1 325
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

С минимальным редактированием кода вы можете создать список словарей на Python и сразу выгрузить его в файл как JSON (при условии, что ваш набор данных достаточно мал, чтобы поместиться в памяти):

import csv
import json
import os

rows = []  # Create list
with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    for line in infile:
         row = dict()
         id, team_name, *team_members = line.split(',')
         row["id"] = id;
         row["team_name"] = team_name;
         row["team_members"] = team_members
         rows.append(row)  # Append row to list

    json.dump(rows[1:], outfile)  # Write entire list to file (except first row)

Кстати, вы не должны использовать id в качестве имени переменной в Python, поскольку это встроенная функция.

Панды с легкостью справятся с этим:

df = pd.read_csv('names.csv', dtype=str)
df['team_members'] = (df['team_members']
                      .map(lambda s: s.split(','))
                      .map(lambda l: [x.strip() for x in l]))
records = df.to_dict('records')
json.dump(records, outfile)
Ответ принят как подходящий

Во-первых, как пропустить заголовок? Это просто:

next(infile) # skip the first line
for line in infile:

Однако вы можете рассмотреть возможность использования csv.DictReader для ввода. Он обрабатывает чтение строки заголовка и использование информации в ней для создания словаря для каждой строки и разделения строк для вас (а также обработки случаев, о которых вы, возможно, не задумывались, например, цитируемый или экранированный текст, который может присутствовать в CSV файлы):

for row in csv.DictReader(infile):
    jsondump(row,outfile)

Теперь о более сложной проблеме.

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

def rows(infile):
    for line in infile:
         row = dict()
         # print(row)
         id, team_name, *team_members = line.split(',')
         row["id"] = id;
         row["team_name"] = team_name;
         row["team_members"] = team_members
         yield row

with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    genjson.dump(rows(infile), outfile)

В документации stdlib json.JSONEncoder есть пример, который делает именно это - хотя и не очень эффективно, потому что сначала использует весь итератор для построения списка, а затем выводит его:

class GenJSONEncoder(json.JSONEncoder):
    def default(self, o):
       try:
           iterable = iter(o)
       except TypeError:
           pass
       else:
           return list(iterable)
       # Let the base class default method raise the TypeError
       return json.JSONEncoder.default(self, o)

j = GenJSONEncoder()
with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    outfile.write(j.encode(rows(infile)))

И действительно, если вы хотите создать весь список, а не кодировать построчно, может быть проще просто явно выполнить литификацию:

with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    json.dump(list(rows(infile)))

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


Но, тем временем, вот прямое решение вашего вопроса, как можно меньше меняя существующий код:

with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    # print the opening [
    outfile.write('[\n')
    # keep track of the index, just to distinguish line 0 from the rest
    for i, line in enumerate(infile):
         row = dict()
         # print(row)
         id, team_name, *team_members = line.split(',')
         row["id"] = id;
         row["team_name"] = team_name;
         row["team_members"] = team_members
         # add the ,\n _before_ each row except the first
         if i:
             outfile.write(',\n')
         json.dump(row,outfile)
    # write the final ]
    outfile.write('\n]')

Этот трюк - особый подход к первому элементу, а не к последнему - упрощает многие проблемы этого типа.


Другой способ упростить задачу - перебрать соседние пары строк, используя небольшую вариацию примера pairwise в документации itertools:

def pairwise(iterable):
    a, b = itertools.tee(iterable)
    next(b, None)
    return itertools.zip_longest(a, b, fillvalue=None)

with open('names.csv', 'r') as infile, open('names1.json','w') as outfile:
    # print the opening [
    outfile.write('[\n')
    # iterate pairs of lines
    for line, nextline in pairwise(infile):
         row = dict()
         # print(row)
         id, team_name, *team_members = line.split(',')
         row["id"] = id;
         row["team_name"] = team_name;
         row["team_members"] = team_members
         json.dump(row,outfile)
         # add the , if there is a next line
         if nextline is not None:
             outfile.write(',')
         outfile.write('\n')
    # write the final ]
    outfile.write(']')

Это так же эффективно, как и предыдущая версия, и концептуально проще, но гораздо более абстрактно.

Что делать, если я не могу проверить nextline, потому что это зависит не от меня? Некоторые фреймворки делают это за меня, если мой элемент - True, он вызывает мою функцию, которая записывает данные в файл. У меня есть несколько файлов, и в зависимости от типа элемента я должен записать их в конкретный файл.

amarynets 12.12.2018 23:32

Похоже, было бы намного проще использовать класс csv.DictReader вместо того, чтобы изобретать колесо:

import csv
import json

data = []
with open('names.csv', 'r', newline='') as infile:
    for row in csv.DictReader(infile):
        data.append(row)

with open('names1.json','w') as outfile:
    json.dump(data, outfile, indent=4)

Содержимое файла names1.json после выполнения (я использовал indent=4, чтобы сделать его более читабельным):

[
    {
        "id": "123",
        "team_name": "Biology",
        "team_members": "Ali Smith, Jon Doe"
    },
    {
        "id": "234",
        "team_name": "Math",
        "team_members": "Jane Smith"
    },
    {
        "id": "345",
        "team_name": "Statistics ",
        "team_members": "Matt P, Albert Shaw"
    },
    {
        "id": "456",
        "team_name": "Chemistry",
        "team_members": "Andrew M, Matt Shaw, Ali Smith"
    },
    {
        "id": "678",
        "team_name": "Physics",
        "team_members": "Joe Doe, Jane Smith, Ali Smith"
    }
]

Другие вопросы по теме