0
\$\begingroup\$

I am parsing a table:

    |-------|
    |Bar|Foo|
    |-------|
    | 5 | 6 |
    |'f'|'g'|
    | 1 | 8 |
    |_______|

I've tried a number of ways of writing a pick function in Python:

#!/usr/bin/env python

from collections import OrderedDict


def pick0(r, k):
    Bar, Foo = r
    return locals().get(k)


def pick1(r, k, h):
    try:
        return r[h.index(k)]
    except ValueError:
        return None


pick2 = lambda r, k, h: OrderedDict(zip(h, r)).get(k)

pick3 = lambda r, ks, h: map(lambda t: t[0] in ks and t[1] or None,
                             OrderedDict(zip(h, r)).iteritems())


if __name__ == '__main__':
    key = 'Foo'
    headers = 'Bar', 'Foo'
    for row in ((5, 6), ('f', 'g'), (1, 8)):
        # Method 0
        print OrderedDict(Bar=row[0], Foo=row[1]).get(key)

        # Method 1
        print pick0(row, key)

        # Method 2
        print pick1(row, key, headers)

        # Method 3
        print pick2(row, key, headers)

        # Method 4
        print pick3(row, ('Foo', 'Bar'), headers)

The last three methods are generalised. The last method allows you to specify multiple keys to pick out.

\$\endgroup\$
  • \$\begingroup\$ Where do the data come from? Are they from a CSV file, by any chance? \$\endgroup\$ – 200_success Oct 26 '14 at 8:29
  • \$\begingroup\$ Yes, that's right \$\endgroup\$ – A T Oct 27 '14 at 2:41
1
\$\begingroup\$

The downside of all the functions, except pick0, is that the caller needs to know all the columns and their order. pick0 is even worse as it is not reusable.

I would rather implement something similar to csv.DictReader that would give me each row as a dict, or perhaps as a namedtuple

If the usage is as simple as in the given example, one could also simply do this:

key_index = headers.index(key)
for row in ((5, 6), ('f', 'g'), (1, 8)):
    print row[key_index]

Other comments:

  • Using locals() in pick0 is dubious. A caller trying to pick k or r would get unexpected results.
  • lambda is for creating nameless functions. Use def when you want to assign a name.
\$\endgroup\$
1
\$\begingroup\$

Given that you stated in the comments that your data come from a CSV file, I recommend using the csv module instead of any of these options.

import csv

with open(filename) as f:
    reader = csv.DictReader(f)
    for row in reader:
        print row['Foo']

DictReader produces a dict rather than an OrderedDict; use reader.fieldnames to discover the original order.

Using the csv module not only reduces the code for you to maintain, it also makes it easier for other programmers to understand your code.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.