0

Let's say I have some data stored as

"this is row -1 and column -1 with value", 12345

in a csv file. (It's not actually stored like that, the point is the first value in the csv is a string that contains the necessary coordinates.)

I should now like to extract these values. I could do a for r in rows: ... but I want to do it with a reduce.

import numpy as np
import scipy as sp
from functools import reduce
import csv
import re


def load(filename):
    with open(filename,'r') as f:
        rows = csv.reader(f)
        next(rows)  # skip header
        coordi,coordj,values = reduce(
                lambda aux,r: ([aux[0]+[i], aux[1]+[j], aux[2] + [int(r[1])]] for i,j in [int(d) for d in re.findall(r"\d+", r[0])]),
                rows,
                [[],[],[]]
                )

        return coordi, coordj, values

Which produces a

TypeError: 'int' object is not iterable

Since

def load(filename):
    with open(filename,'r') as f:
        rows = csv.reader(f)
        next(rows)  # skip header
        coordi,coordj,values = reduce(
                lambda aux,r: ([aux[0]+[-1], aux[1]+[-1], aux[2] + [int(r[1])]]),
                rows,
                [[],[],[]]
                )

        return coordi, coordj, values

Works, I can only guess that there's something about i,j python isn't happy with.

Which I have no idea why because

for r in rows:
   i,j = [int(d) for d in re.findall(r"\d+", row[0])]

works like a charm.

How do I make this work?

User1291
  • 7,664
  • 8
  • 51
  • 108

2 Answers2

1

Well, there is something about i, j that Python isn't happy with, and that's because you're passing it one thing instead of two.

The result from your inner list comprehension is a list of ints; you can't iterate over that with for i, j in ....

Edit

for r in rows assigns the whole of each row to r; in this case r is a list of elements. But for i, j in ... attempts to iterate over its argument, and for each element it attempts to assign the first member to i and the second to j; but there simply aren't first or second members, there is simply an int. You are trying to add an extra level of iteration where there isn't one.

If you have exactly two ints, then you shouldn't be iterating at all. This can't be expressed as a list comprehension, and probably should be a separate function rather than a lambda:

def reduction(aux, r):
   i,j = [int(d) for d in re.findall(r"\d+", r[0])]
   return [aux[0]+[i], aux[1]+[j], aux[2] + [int(r[1])]]
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
1

@Daniel Roseman is right. Check the For loop in debug mode.

The below code might help you.

enter image description here

Bhuvan Kumar
  • 554
  • 1
  • 7
  • 23
  • Hm ... Thought I could bypass this by placing the ``[int(d) for d in re.findall(r"\d+", r[0])]`` within a list (i.e. ``[[int(d) for d in re.findall(r"\d+", r[0])]]``). But then I get ``'generator' object not subscriptable``. You wouldn't happen to know a way around that? – User1291 Mar 23 '17 at 12:17
  • check the value of int(d) and r[0]. Any one of those might be rising the error. Debug with breakpoint in error line will help you to resolve error faster. – Bhuvan Kumar Mar 23 '17 at 12:53