Search code examples
pythonfix-protocol

Assigning multiple values to a single dictionary key python


i'm trying to assignee repeating FIX tag values to a single dictionary key.

the line i'm reading contains multiple <269> FIX tags whit different values:

<class 'list'>: ['8=FIX.X.X', '9=XXX', '35=V', '34=XXXXXX', '49=XXX.XXXXX.X', '56=XXX.XXXXX', '52=XXXXXXXX-XX:XX:XX.XXX', '128=XXXX,XXXX', '262=XXX/XXX-XXXXXXXXXX', '263=X', '265=X', '1021=X', '264=X', '267=X', '269=0', '269=1', '146=X', '55=XXX/XXX', '167=XXXXX', '1300=X', '63=X', '10=XXX']

each time i run my code 269: 0 is overwritten by 269: 1 i'm looking for a way to append both values to the same key "269: 0,1" (unfortunately wasn't able to find a method i understand on similar question threads).

here is my code:

import os
import time
import csv

csvPath = 'C:/""/""/""/""/FixTakerLogs/'
logsPath = 'C:/""/""/""/""/FixTakerLogs/'

print('[START]:', 'MsgMarketDataRequest.csv')
fileMarketDataRequest = open('C:/Users/apanasenko/Desktop/LOGS/FixTakerLogs/MsgMarketDataRequest.log','r')
with open(csvPath + 'MsgMarketDataRequest.csv', 'w', newline='') as csvLogon:
    msgDict = {'8': '','9': '','35': '','49': '','56': '','34': '','52': '','128': '','262': '','263': '','264': '',
                 '265': '','267': '','269': '','146': '','55': '','167': '','63': '','12008': '','64': '','193': '',
                 '271': '','1201': '','1202': '','1300': '','10': ''}
    csvWriter = csv.DictWriter(csvLogon, msgDict.keys())
    csvWriter.writeheader()
    for line in fileMarketDataRequest:
        line = line.rstrip()
        line = line.split(';')
        X = len(line) - 1
        line = line[0:X]
        for tag in line:
            tag = tag.split('=')
            msgDict[tag[0]] = tag[1]
        csvWriter.writerow(msgDict)
        msgDict = {}
csvLogon.close()
print('[END]:', 'MsgMarketDataRequest.csv')

Thank You.


Solution

  • You are perhaps familiar with the list? It's Python's mutable multi-value store, which you can iterate over all the values in and so on. For example, one possible replacement for your code that reads

    msgDict = {'8': '','9': '','35': '','49': '','56': '','34': '','52': '','128': '','262': '','263': '','264': '',
                 '265': '','267': '','269': '','146': '','55': '','167': '','63': '','12008': '','64': '','193': '',
                 '271': '','1201': '','1202': '','1300': '','10': ''}
    

    would use a dictionary comprehension driven by a list of key values to make the dictionary initialisation more compact (and, hopefully, more readable):

    msg_dict = {key: '' for key in ['8', '9', '35', ... , '1'0']}
    

    You'll see I prefer the naming style suggested in PEP 8, but style isn't as important as writing working code to start with - there's plenty of time to learn to polish later. It's just become a habit so I thought I'd mention it.

    Along similar lines (it's always best to write readable code when you can so this is just a hint - it works the same as your code) you might replace

    X = len(line) - 1
    line = line[0:X]
    

    with

    line = line[:-1]
    

    There's no need to use the len function when negative indexing will do, but if you haven't come across it, it's worth knowing about.

    The key portion of your code is the one that reads

    for tag in line:
        if tag not in line:
            tag = tag.split('=')
            msgDict[tag[0]] = tag[1]
    

    That last assignment is guaranteed to overwrite any existing key. But you could use a list for the values by instead initialising the values of msg_dict to an empty list like so:

    msg_dict = {key: [] for key in ['8', '9', '35', ... , '1'0']}
    

    and appending the tags as you find them:

    for tag in line:
        name, val = tag.split('=')
        if name in msgDict:
            msgDict[name].append(val)
    

    You'll see I used an "unpacking assignment" so I could use names rather than indexing - again, such techniques help readability. When you have iterated over all the tags, each key in msgDict will be a list of all the values encountered.

    Of course you will then have the problem of how to sensibly write that to a CSV file so you can read it back (hint: you don't have to use CSV files for everything!). But I hope that's progress of a sort. Good luck!