0

更新:ソリューション

私はなんとか次のコードを動作させることができました

import collections
from lxml import etree
## Up here is code for getting an .xml input file from the user, opening that file, etc. ##
## This part is in a for loop that goes over each order in the xml file ##
## This all would have an extra indent because it is under this: for order in root.xpath('//order'): ##
itemlist = []
    ## This part looks through the .xml file for the order it is currently iterating and puts the items into a list ##
    for element in order.iter('items'):
        itemlist.append ("%s" % str.upper((element.get('type'))))
    ## This part 'sanitizes' the order name from the .xml file for use as a key ##
    for element in order.iter('order'):
        ordername = element.get('name')
        strippedordername = re.sub('[/\()!@#$%^&*()]', '', ordername)
        allordernames.append (strippedordername)
        print strippedordername
        #print itemlist
        ## This bit compiles a shopping list of items in a special dict subclass called a Counter. ##
        ordercounter.update(itemlist)
        ## This part makes a dict with order names for its keys and their corresponding Counter of items as its values ##
        ordersdictsdict[strippedordername] = collections.Counter(itemlist)
zeros = dict((k,0) for k in ordercounter.keys())
for cntr in ordersdictsdict.values():
    cntr.update(zeros)

#print ordercounter
#print ordersdictsdict
key_order = list(ordercounter.keys())
print key_order
with open(out_file,'w') as fout:
    fout.write('Order,'+','.join(key_order)+'\n')
    fout.write('Totals,'+','.join(str(ordercounter[k]) for k in key_order)+'\n') 
    for ordername,dct in ordersdictsdict.items():
        fout.write(ordername+','+','.join(str(dct[k]) for k in key_order)+'\n')
fout.closed

出力は次のようになります。

Order,Spam,Eggs,Baked Beans,Sausage
Totals,13,1,1,1
Order for Joe,2,1,0,1
Order for Jill,11,0,1,0

私が持っているもの

私のスクリプトは入力xmlファイルを受け取り、それを解析して、注文名を探し、次に注文内容を探します。1つのxmlファイルに複数の注文が含まれる場合があります。次に、すべての注文のすべてのアイテムを集計し、総買い物リストを表示するカウンターがあります。

これらの2つのサンプル注文を考えると:

Order for Joe: Spam, Egg, Sausage, Spam
Order for Jill: Spam, Spam, Spam, Spam, Spam, Spam, Spam, Beaked Beans, Spam, Spam, Spam, Spam

カウンターは次のようになります。 Counter({'Spam': 13,'Baked Beans' 1, 'Egg': 1, 'Sausage': 1})

次に、これをcsvファイルに書き込んで、次のようにします。

Item,Count
Spam,13
Baked Bean,1
Egg,1
Sausage,1

私が欲しいもの

総買い物リストは素晴らしいですが、出力csvファイルを拡張して、各注文名の買い物リストも含めたいと思います。注文名が行であるか列であるかは関係ありません。また、この順序ではないアイテムのセルが空である0か空であるかは気にしませんが0、例では使用します。

行として注文名を使用した望ましい出力の例

Order Name,Spam,Baked Beans,Egg,Sausage
Totals,13,1,1,1
Order for Joe,2,0,1,1
Order for Jill,11,1,0,0

注文名を列として使用した望ましい出力の例

Item,Totals,Order for Joe,Order for Jill
Spam,13,2,11
Baked Beans,1,0,1
Egg,1,1,0
Sausage,1,1,0

ノート

このスクリプトを任意の入力ファイルで機能させたいのですが、もちろん、入力に注文が1つしかない場合は、Totalsその注文名と一致します。最初に総計カウンターを作成し(問題の注文で可能なすべてのアイテムを取得できるように)、次に各注文のカウントをcsvに入力する必要があります。つまり、次の入力ファイルの注文に異なるアイテムが含まれている可能性があるため、ハードコードされたアイテムを書き込みてcsvファイルを開始することはできません。

4

3 に答える 3

1

ネストされたcollections.defaultdictセットを使用して0で初期化することをお勧めします。

入力ファイルが次のようになっているとします。

Order for Joe: Spam, Egg, Sausage, Spam
Order for Jill: Spam, Spam, Spam, Spam, Spam, Spam, Spam, Beaked Beans, Spam, Spam, Spam, Spam

次に、次のように合計と個々の注文数の両方を取得できます。

answer = collections.defaultdict(collections.defaultdict(int))
with open('path/to/input') as infile:
    for line in infile:
        name, _, orders = line.partition(":")
        name = name.rpartition(' ')[-1]
        orders = orders.strip().split(',')
        for order in orders:
            answer['total'][order] += 1
            answer[name][order] += 1
with open('path/to/output') as outfile:
    keys = sorted(answer['total'])
    outfile.write("Order Name,%s" %(','.join(keys)))
    outfile.write('total,%s' %(','.join(answer['total'][k] for k in keys)))
    for name, orders in answer.iteritems():
        if name != 'total':
            outfile.write('%s,%s' %(name, ','.join(answer[name][k] for k in keys)))
于 2012-12-13T15:52:09.923 に答える
1

Counter入力ファイルのすべての行にを使用できないのはなぜですか?

from collections import Counter
d = {}  
#*1* Alternatively, could use : d = defaultdict(Counter)
with open(inputfile) as input_file:
    for line in input_file:
        for_who, items = line[:-1].split(':',1)
        d[for_who] = Counter(items.split(','))  
        #Alternatively, if using defaultdict at *1*, d.update(items.split(','))
        #This allows "joe" to register multiple shopping lists which get summed into 1

#get totals by `sum`ming your Counters values:
totals = sum(d.values())

#Now add a 0-dict to each of the dictionaries just to make sure they have all the keys
zeros = dict((k,0) for k in totals)
for cntr in d.values():
    cntr.update(zeros)

key_order = list(totals.keys())  #list for py2k
with open(output_file,'w') as fout:
    fout.write('Order '+','.join(key_order)+'\n')
    fout.write('Totals,'+','.join(str(totals[k]) for k in key_order)+'\n') 
    for person,dct in d.items():
        fout.write(person+','+','.join(str(dct[k]) for k in key_order)+'\n') 

アイテムの名前にコンマを含めることができる場合は、引用符を処理するためにもう少し注意が必要な場合があります(csvそのようなもののモジュールを考えてください)が、これは開始するのに適した場所です。

于 2012-12-13T15:50:52.140 に答える
1

csv.DictWriterを使用して出力を管理できます。

個々の注文ごとにカウンターの長いリストに加えて、合計を含む1つのカウンターを組み立てます。

入力を読んでいるときに、次のように入力を処理します。

  1. .updateを使用して、注文の各項目を「合計」辞書に追加します。
  2. 新しいものを作成して、注文の各アイテムを「注文」辞書に追加します
  3. 注文名を使用して、各カウンターに「注文名」キーを追加します
  4. フィールド名をtotals.keys()にして、DictWriterインスタンスを作成します
于 2012-12-13T15:51:31.337 に答える