0

I'm trying to write data from a list of lists to a csv file. This is a simplified version of what I have

class Point(object): 
    def __init__(self, weight, height):
        self.weight = weight
        self.height = height
    def get_BMI(self):
        return (self.weight * self.height) / 42  # this is not how you calculate BMI but let's say

myList = [[Point(30, 183)],[Point(63, 153)]]

Because of the way the data is set up, I store the points in a nested loop. If I wanted to access the first point object’s BMI, I would type

myList[0][0].get_BMI()

I want to write each point's BMI to a CSV (delimited by a comma). How do I do that?

Here's how I thought but it isn't exactly straight forward:

import csv
with open('output.csv', 'w') as csvfile:
    writer = csv.writer(csvfile)
    writer.writerows(myList)

It doesn't return any error however it doesn't actually create the CSV file either. Also I want to write the values in myList[i][j].get_BMI() to file. I don't have a problem with permissions because I use Spyder (python IDE) as root. Right now I'm just running the script through the Spyder console but it should still work and output the CSV file.

4 Answers 4

1

writerows expects a list of list of strings or numbers. You should start by creating a list with the BMI values so that they can get written into your csv file:

import csv
BMIs = [[point.get_BMI() for point in points] for points in myList]
with open('output.csv', 'w') as csvfile:
    writer = csv.writer(csvfile)
    writer.writerows(BMIs)
Sign up to request clarification or add additional context in comments.

Comments

1

You can do this with writerows, as it expects a list of rows - each row should be formatted as per the dialect parameter to csv.writer, which can be ignored in this case without fear of any backfiring.

So writerows can take a structure that looks like myList. The problem is that you need to access all the points and grab their BMIs (this can be done in a list comprehension)

To illustrate how writerows can be used (and to add a number to each point, so that all your rows don't have just one entry (which would be frustrating), I added the call to enumerate.

Therefore, you no longer need complex loops or any such. Enjoy:

myList = [[Point(30, 183)],[Point(63, 153)]]

with open('output.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    writer.writerows(enumerate(p.get_BMI() for p in itertools.chain.from_iterable(myList)))

Comments

1

There are three issues:

  1. The nested lists must be flattened. To accomplish this, use itertools.chain.from_iterable.

  2. The row data for the CSV must be customized. To accomplish this, use list comprehensions.

  3. output.csv is not being created. I suspect that the output.csv is being created but being placed in an unexpected location. You could try hardcoding a full path for testing to see if this is the case.

Here is code that demonstrates #1 and #2:

import csv
from itertools import chain

with open('output.csv', 'w') as csvfile:
    writer = csv.writer(csvfile)
    flattenedList = chain.from_iterable(myList)

    writer.writerows((pt.weight, pt.height, pt.get_BMI()) for pt in flattenedList)

2 Comments

For point 3, I believe that csv is silently ignoring object that are neither a string nor a number and then decided to not write anything.
@FrancisColas The open call just by itself will create an empty file and the objects will have a string representation such as <__main__.Point object at 0x022E02D0> that csv will use by default (via the equivalent of the str operator).
-1
myList = [[Point(30, 183)],[Point(63, 153)]]

with open('output.csv', 'w') as outfile:
    writer = csv.writer(outfile,delimiter=',')
    for i in myList:
         writer.writerow([i]) 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.