Защо python не чете въвеждането на stdin като речник?

Сигурен съм, че правя нещо глупаво тук, но ето го. Работя върху задание за класа за моя клас Udacity „Въведение в Map Reduce и Hadoop“. Нашата задача е да направим съпоставител/редуцент, който ще брои срещанията на дума в нашия набор от данни (тялото на публикациите във форума). Имам идея как да направя това, но не мога да накарам Python да чете stdin данни в редуктора като речник.

Ето моят подход досега: 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()

след това броят на публикациите във форума отива в stdout като: {'this': 1, 'is': 1, 'one': 1, 'sentence': 2}

тогава редукторът трябва да чете в този stdin като речник

#!/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

Което означава (ако разбирам правилно), че се чете във всеки ред не като dict, а като текстов низ. Как мога да накарам python да разбере, че редът за въвеждане е dict? Опитах да използвам Counter и defaultdict, но все още имах същия проблем или го прочетох във всеки знак като елемент от списъка, което също не е това, което искам.

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

Благодаря, JR


person jrubins    schedule 12.08.2014    source източник
comment
Трябва да обмислите четене на низа, след което да го анализирате. Ако направите това, просто трябва да потърсите низ за анализ като dict python. Може би това?   -  person keyser    schedule 12.08.2014
comment
Низът не е валиден аргумент за конструктор dict(). Ще трябва да използвате нещо като ast.literal_eval(), за да анализирате 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, но причината е, че това е програма за картографиране/намаляване, така че е проектирана да се разпространява, така че не мога да имам само една програма, която брои всички стойности (което би било лесно) . Вместо това бих могъл да имам множество преобразуватели, които отчитат стойностите на различни секции на входния файл, които след това получават изход към множество редуктори (или в този случай един редуктор), който сумира всички стойности, които му дават преобразувателите.   -  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