pceccon
pceccon

Reputation: 9844

Iterator inside DictWriter.writerow

I'm trying to process a data struct as follows:

dict<ID, actions>

where actions is a list of dictionaries, and each of them contain two pairs (at least): 'gameCode':value, 'gameTime':value.

So my data is like:

{user1: [{gameCode : 1, gameTime : 1}, {gameCode : 2, gameTime : 2}], 
user2: [{gameCode : 1, gameTime : 1}, {gameCode : 2, gameTime : 2}]}

This data come from a log in which each row represents one action.

I have to produce an output as the following:

ID | action | time | action | time ...

I was wondering how could I write these pairs of action/times in a pythonic way, maybe using a list comprehension. This is what I have so far:

    event = 'gameCode'
    data = 'gameTime'

    # Open the .csv file and creates a dict of actions
    with open(file_path, 'rb') as csvfile:
        spamreader = csv.DictReader(csvfile, delimiter='\t')
        for row in spamreader:
            # Add an empty list for 'userID' if it is not registered yet in dict
            user = row['userID']
            actions = Users.get(user, []) 
            # Delete the 'userID' from the information
            del row['userID']
            # Add a register of actions for this user
            actions.add(row)
            # Update its values
            users[user] = actions   

     # Sort each list of actions based on time      
     for key, value in users.iteritems(): 
        users[key] = sorted(value, key=lambda k: k[data])

     # Write a .csv to be consumed by the app   
     with open('eventsInput.csv', 'w') as csvfile:
         csv.writer(csvfile, delimiter=' ')
         for key, value in users.iteritems(): 
            actions = [[d[event], d[data]] for d in value]
            writer.writerow([key, 0, 0, 0, 0, [action for action in actions]])

I'm stuck at this last line.

With this, I get this output:

L11-13 0 0 0 0 "[['1002', '358']]"

But I don't want nothing but 1002 358 (i.e., no " , ' [ etc)

Upvotes: 0

Views: 359

Answers (3)

pceccon
pceccon

Reputation: 9844

After some researcher and a lot of trials, I found out that I can accomplish what I want with this piece of code:

with open('eventsInput.csv', 'w') as csvfile:
    writer = csv.writer(csvfile, delimiter='\t')
     for key, value in users.iteritems(): 
        # That was what changed the result
        actions = list(chain.from_iterable((d[event], d[data]) for d in value))
        print actions
        writer.writerow([key, 0, 0, 0, 0] + [action for action in actions])

Just don't know why I can't do:

actions = [chain.from_iterable((d[event], d[data]) for d in value)]

Upvotes: 1

AChampion
AChampion

Reputation: 30278

To fix your updated code, you can just add lists:

writer.writerow([key, 0, 0, 0, 0] + [action for action in actions]])

But this may cause issues on read because you may have variable number of fields per row, unless len(actions) is a constant.

Upvotes: 0

AChampion
AChampion

Reputation: 30278

Unfortunately you can't have multiple fieldnames with the same value in a DictWriter, you could revert to a normal csv writer (though you might have to deal with uneven lengths of action time tuples for a specific id) or consider that for any id you have a list of actions and a list of times:

from csv import DictWriter
data = [{'id': 1, 'actions':[1,2,3], 'times': [1,2,3]},
        {'id': 2, 'actions':[4,5,6], 'times': [4,5,6]}]
with open('fred.csv', 'w+') as f:
    writer = DictWriter(f, ['id', 'actions', 'times'])
    writer.writeheader()
    writer.writerows(data)

fred.csv

id,actions,times
1,"[1, 2, 3]","[1, 2, 3]"
2,"[4, 5, 6]","[4, 5, 6]"

When you read it in, you can zip actions and times to get them back together.

Upvotes: 1

Related Questions