更新:ソリューション
私はなんとか次のコードを動作させることができました
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ファイルを開始することはできません。