Почему python не читает ввод stdin как словарь?

Я уверен, что я делаю что-то глупое здесь, но вот идет. Я работаю над классным заданием для своего класса Udacity «Введение в Map Reduce и Hadoop». Наша задача состоит в том, чтобы сделать сопоставитель/редьюсер, который будет подсчитывать вхождения слова в нашем наборе данных (тело сообщений на форуме). У меня есть идея, как это сделать, но я не могу заставить Python читать данные стандартного ввода в редуктор как словарь.

Вот мой подход на данный момент: Mapper считывает данные (в данном случае в коде) и выдает словарь word:count для каждого сообщения на форуме:

#!/usr/bin/python
import sys
import csv
import re
from collections import Counter


def mapper():
    reader = csv.reader(sys.stdin, delimiter='\t')
    writer = csv.writer(sys.stdout, delimiter='\t', quotechar='"', quoting=csv.QUOTE_ALL)

    for line in reader:
        body = line[4]
        #Counter(body)
        words = re.findall(r'\w+', body.lower())
        c = Counter(words)
        #print c.items()
        print dict(c)





test_text = """\"\"\t\"\"\t\"\"\t\"\"\t\"This is one sentence sentence\"\t\"\"
\"\"\t\"\"\t\"\"\t\"\"\t\"Also one sentence!\"\t\"\"
\"\"\t\"\"\t\"\"\t\"\"\t\"Hey!\nTwo sentences!\"\t\"\"
\"\"\t\"\"\t\"\"\t\"\"\t\"One. Two! Three?\"\t\"\"
\"\"\t\"\"\t\"\"\t\"\"\t\"One Period. Two Sentences\"\t\"\"
\"\"\t\"\"\t\"\"\t\"\"\t\"Three\nlines, one sentence\n\"\t\"\"
"""

# This function allows you to test the mapper with the provided test string
def main():
    import StringIO
    sys.stdin = StringIO.StringIO(test_text)
    mapper()
    sys.stdin = sys.__stdin__

if __name__ == "__main__":
    main()

количество сообщений на форуме затем переходит в стандартный вывод, например: {'this': 1, 'is': 1, 'one': 1, 'sentence': 2}

тогда редуктор должен читать этот стандартный ввод как словарь

#!/usr/bin/python
import sys
from collections import Counter, defaultdict
for line in sys.stdin.readlines():
    print dict(line)

но это не удается, выдавая мне это сообщение об ошибке: ValueError: dictionary update sequence element #0 has length 1; 2 is required

Это означает (если я правильно понимаю), что он читает в каждой строке не как диктовку, а как текстовую строку. Как я могу заставить python понять, что строка ввода является диктовкой? Я пытался использовать Counter и defaultdict, но у меня все еще была та же проблема или он читался в каждом символе как элемент списка, что также не то, что я хочу.

В идеале я хочу, чтобы картограф читал словарь каждой строки, а затем добавлял значения следующей строки, чтобы после второй строки значения были {'this':1,'is':1,'one':2,'sentence':3,'also':1} и так далее.

Спасибо, Дж.Р.


person jrubins    schedule 12.08.2014    source источник
comment
Вам следует прочитать строку, затем проанализировать ее. Если вы это сделаете, вам просто нужно найти строку синтаксического анализа как dict python. Может быть, это?   -  person keyser    schedule 12.08.2014
comment
Строка не является допустимым аргументом для конструктора dict(). Для анализа Словарь Python из строки. Или, возможно, сериализуйте и десериализуйте свою структуру данных с помощью модуля json.   -  person Lukas Graf    schedule 12.08.2014
comment
ваш line - это одно строковое значение.   -  person Tritium21    schedule 12.08.2014
comment
Почему бы тебе просто не позвонить mapper? Это то, что делает исходный код.   -  person nneonneo    schedule 12.08.2014
comment
Я действительно не понимаю, почему этот вопрос был отклонен. Это может быть странная хитрость, но сам вопрос в порядке, он явно написан с некоторой осторожностью и содержит все необходимое для воспроизведения проблемы.   -  person Lukas Graf    schedule 12.08.2014
comment
Спасибо, Лукас, кейсер. В итоге я использовал метод ast.literal_eval. Это решило мою проблему. Я опубликую решение ниже. Это определенно странная штуковина, Лукас, nneonneo, но причина в том, что это программа map/reduce, поэтому она предназначена для распространения, поэтому я не могу просто иметь одну программу, которая подсчитывает все значения (что было бы легко) . Вместо этого я мог бы иметь несколько преобразователей, подсчитывающих значения различных разделов входного файла, которые затем передают вывод нескольким редюсерам (или, в данном случае, одному редюсеру), который суммирует все значения, которые ему дают преобразователи.   -  person jrubins    schedule 12.08.2014


Ответы (1)


Благодаря @keyser у меня сработал метод ast.literal_eval(). Вот что у меня есть сейчас:

#!/usr/bin/python
import sys
from collections import Counter, defaultdict
import ast
lineDict = {}
c = Counter()
for line in sys.stdin.readlines():
    lineDict = ast.literal_eval(line)
    c.update(lineDict)
print c.most_common()
person jrubins    schedule 12.08.2014