Search code examples
pythonpython-2.7list-comprehensionnested-loops

Getting rid of an extra list in a list comprehension with nested loops


I have a pretty inelegant nested loop to clean up data from a csv - is there a better/more pythonic way to accomplish the below?

data = [[map(int, i.split(',')) for i in (item.strip() 
                                for item in line.rstrip('\n').split('\t'))][0] 
                                for line in open('input1.csv')]

output: [[8, -11, 1], [7, 7, -1], [12, -20, 1], [14, -3, -1], [12, 8, -1], [1, -12, 1], [15, 5, -1], [7, -10, 1], [10, 4, -1], [6, 2, 1], [8, 12, -1], [2, 20, -1], [1, -12, 1], [9, 8, -1], [3, 3, 1], [5, 6, 1], [1, 11, 1]]

In particular, in the second for loop I call index 0 of the list created by the last for loop (not sure that's the right terminology?). Originally I had the below code, but this was generating a doubly nested list. I stuck in the [0] to flatten the double nesting, but this seems like a pretty bad solution.

[[map(int, i.split(',')) for i in (item.strip() 
                         for item in line.rstrip('\n').split('\t'))] 
                         for line in open('input1.csv')]

output: [[[8, -11, 1]], [[7, 7, -1]], [[12, -20, 1]], [[14, -3, -1]], [[12, 8, -1]], [[1, -12, 1]], [[15, 5, -1]], [[7, -10, 1]], [[10, 4, -1]], [[6, 2, 1]], [[8, 12, -1]], [[2, 20, -1]], [[1, -12, 1]], [[9, 8, -1]], [[3, 3, 1]], [[5, 6, 1]], [[1, 11, 1]]]

Input data from csv below:

8,-11,1
7,7,-1
12,-20,1
14,-3,-1
12,8,-1
1,-12,1
15,5,-1
7,-10,1
10,4,-1
6,2,1
8,12,-1
2,20,-1
1,-12,1
9,8,-1
3,3,1
5,6,1
1,11,1

Solution

  • As wim mentioned in his comment, this is not something you need to solve yourself! I wrote your csv to a file called eg.csv, and ...

    >>> import csv
    >>> list(csv.reader(open('eg.csv')))
    [['8', '-11', '1'], ['7', '7', '-1'], ['12', '-20', '1'], ['14', '-3', '-1'], ['12', '8', '-1'], ['1', '-12', '1'], ['15', '5', '-1'], ['7', '-10', '1'], ['10', '4', '-1'], ['6', '2', '1'], ['8', '12', '-1'], ['2', '20', '-1'], ['1', '-12', '1'], ['9', '8', '-1'], ['3', '3', '1'], ['5', '6', '1'], ['1', '11', '1']]
    

    if you wanted them to be integers, you can do something like:

    >>> [[int(col) for col in row] for row in csv.reader(open('eg.csv'))]
    # or
    >>> map(lambda x: map(int, x), csv.reader(open('eg.csv')))
    # or
    >>> [map(int, row) for row in csv.reader(open('eg.csv'))]
    # to get
    [[8, -11, 1], [7, 7, -1], [12, -20, 1], [14, -3, -1], [12, 8, -1], [1, -12, 1], [15, 5, -1], [7, -10, 1], [10, 4, -1], [6, 2, 1], [8, 12, -1], [2, 20, -1], [1, -12, 1], [9, 8, -1], [3, 3, 1], [5, 6, 1], [1, 11, 1]]
    

    Unfortunately the builtin csv module does not attempt to deal with any type conversions.