Написать ключ для разделения CSV на основе значения в словаре

1

[Использование Python3] У меня есть файл csv, который имеет два столбца (адрес электронной почты и код страны; script делается для того, чтобы фактически сделать его двумя столбцами, если не в случае с исходным файлом), что я хотите разделить на значение во втором столбце и вывести их в отдельные файлы csv.

[email protected]       us      ==> output-us.csv
[email protected]            de      ==> output-de.csv
[email protected]       es      ==> output-es.csv
[email protected]        it      ==> output-it.csv
[email protected]          fr      ==> output-fr.csv
[email protected]    gb      ==> output-gb.csv
[email protected]            us      ==> output-us.csv
...                             ...     ...

В настоящее время мой код делает это, но вместо того, чтобы писать каждый адрес электронной почты в csv, он перезаписывает ранее размещенное электронное письмо. Может кто-нибудь помочь мне с этим?

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

Спасибо заранее!

код:

import csv

def tsv_to_dict(filename):
    """Creates a reader of a specified .tsv file."""
    with open(filename, 'r') as f:
        reader = csv.reader(f, delimiter='\t') # '\t' implies tab
        email_list = []
        # Checks each list in the reader list and removes empty elements
        for lst in reader:
            email_list.append([elem for elem in lst if elem != '']) # List comprehension
        # Stores the list of lists as a dict
        email_dict = dict(email_list)
    return email_dict

def count_keys(dictionary):
    """Counts the number of entries in a dictionary."""
    return len(dictionary.keys())

def clean_dict(dictionary):
    """Removes all whitespace in keys from specified dictionary."""
    return { k.strip():v for k,v in dictionary.items() } # Dictionary comprehension

def split_emails(dictionary):
    """Splits out all email addresses from dictionary into output csv files by country code."""
    # Creating a list of unique country codes
    cc_list = []
    for v in dictionary.values():
        if not v in cc_list:
            cc_list.append(v)

    # Writing the email addresses to a csv based on the cc (value) in dictionary
    for key, value in dictionary.items():
        for c in cc_list:
            if c == value:
                with open('output-' +str(c) +'.csv', 'w') as f_out:
                    writer = csv.writer(f_out, lineterminator='\r\n')
                    writer.writerow([key])
Теги:
python-3.x
dictionary

3 ответа

1
Лучший ответ

Это можно упростить, используя defaultdict:

import csv
from collections import defaultdict

emails = defaultdict(list)

with open('email.tsv','r') as f:
   reader = csv.reader(f, delimiter='\t')
   for row in reader:
      if row:
         if '@' in row[0]:
           emails[row[1].strip()].append(row[0].strip()+'\n')

for key,values in emails.items():
   with open('output-{}.csv'.format(key), 'w') as f:
       f.writelines(values)

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

Словарь emails содержит ключ для каждого кода страны и список для всех соответствующих адресов электронной почты. Чтобы убедиться, что адреса электронной почты напечатаны правильно, мы удаляем любые пробелы и добавляем разрыв строки (это значит, что мы можем использовать writelines позже).

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

  • 0
    Спасибо, Бурхан, твой код у меня не совсем работает. Я получаю сообщение об ошибке IndexError: list index out of range . PS Я удалил 'b' из 'rb' как использую Python3.
  • 0
    Хм, в вашем файле могут быть пустые строки с электронными письмами. Я обновил ответ.
Показать ещё 3 комментария
1

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

Простым способом избежать этого является одновременное открытие всех выходных файлов для записи и хранения их в словаре с кодом страны. Аналогично, у вас может быть другой, который связывает каждый код страны с объектом csv.writer для выходного файла этой страны.

Обновление:. Хотя я согласен с тем, что подход Burhan, вероятно, выше, я чувствую, что у вас есть идея, что мой более ранний ответ был чрезмерно длинным из-за всех комментариев, которые у него были, поэтому здесь другая версия по сути, та же логика, но с минимальными комментариями, чтобы вы могли лучше определить ее разумно короткую истинную длину (даже с помощью контекстного менеджера).

import csv
from contextlib import contextmanager

@contextmanager  # to manage simultaneous opening and closing of output files
def open_country_csv_files(countries):
    csv_files = {country: open('output-'+country+'.csv', 'w') 
                   for country in countries}
    yield csv_files
    for f in csv_files.values(): f.close()

with open('email.tsv', 'r') as f:
    email_dict = {row[0]: row[1] for row in csv.reader(f, delimiter='\t') if row}

countries = set(email_dict.values())
with open_country_csv_files(countries) as csv_files:
    csv_writers = {country: csv.writer(csv_files[country], lineterminator='\r\n')
                    for country in countries}
    for email_addr,country in email_dict.items():
        csv_writers[country].writerow([email_addr])
  • 0
    Спасибо Мартино! Ваше решение сделало именно то, что я намеревался!
  • 0
    Matthijs: Если вы считаете, что мой ответ заслуживает внимания, пожалуйста, рассмотрите возможность его повторного голосования (если у вас достаточно репутации). Благодарю.
Показать ещё 1 комментарий
0

Не ответ на Python, но, возможно, вы можете использовать это решение Bash.

$ while read email country
do
  echo $email >> output-$country.csv
done < in.csv

Это считывает строки из in.csv, разделяет их на две части email и country и добавляет (>>) к email в файл с именем output-$country.csv.

  • 0
    Спасибо за это нестандартное мышление, но оно не отвечает требованию выполнения дополнительных действий со списками электронной почты (например, очистка списка электронных писем).
  • 0
    Какой вид уборки вам нужен в деталях?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню