baobobs
baobobs

Reputation: 703

Converting strings of tuples within list of lists to list items in Python

List l contains items consisting of two types of lists, the first being acceptable lists consisting of strings and the second consisting of strings of tuples containing strings. All lists of the second type are of the same length - 2. I want to convert all lists of the second type to the same convention as the first type, as demonstrated below (l2 is the updated list).

Edit: I should clarify that the actual list I am dealing with as far more than two items, so I need a loop function to accommodate this.

l = [["('N', '', 'SHOWERS', '', 'RD', '11734', '11734', '', '')", "('61060', '61060')"], ['', '', 'NORA', '', 'RD', '10301', '10999', '10400', '10998', '61089', '61089']]

l2 = [['N', '', 'SHOWERS', '', 'RD', '11734', '11734', '', '', '61060', '61060'], ['', '', 'NORA', '', 'RD', '10301', '10999', '10400', '10998', '61089', '61089']]

The following only gets me so far:

from csv import reader
from cStringIO import StringIO

l2 = []

for i in l:
    if len(i) == 2:
        filestr = StringIO(i[0] + i[1])
        csv_reader = reader(filestr, quotechar="'")
        for t in csv_reader:
            l2.append(t)
    else:
        l2.append(i)

Upvotes: 0

Views: 345

Answers (4)

Francis Avila
Francis Avila

Reputation: 31621

This is not a csv problem, since you don't have a csv. (In fact you confused me for some time because I was trying to imagine what the csv file looked like!)

  1. Establish a "test" of whether a list needs normalization (is_tuple_string_row function below).
  2. Use ast.literal_eval to safely convert the string-of-tuple into an actual tuple.
  3. Use chain.from_iterable to combine all the tuples into a single sequence.

Full code below implemented as the generator normalized_list().

l = [["('N', '', 'SHOWERS', '', 'RD', '11734', '11734', '', '')", "('61060', '61060')"], ['', '', 'NORA', '', 'RD', '10301', '10999', '10400', '10998', '61089', '61089']]

l2 = [['N', '', 'SHOWERS', '', 'RD', '11734', '11734', '', '', '61060', '61060'], ['', '', 'NORA', '', 'RD', '10301', '10999', '10400', '10998', '61089', '61089']]

import ast
from itertools import imap, chain


def is_tuple_string_row(L):
    """Return whether list L is a list of strings containing tuples"""
    return len(L)==2 and all(s.startswith("('") and s.endswith("')") for s in L)


def normalized_list(L):
    """Yield lists in sequence L as lists of strings

    Normalizes a list of strings of tuples down to a simple list of strings
    """
    for item in L:
        if is_tuple_string_row(item):
            yield list(chain.from_iterable(imap(ast.literal_eval, item)))
        else:
            yield item


# You can iterate efficiently
for item in normalized_list(l):
    print item

# or you can put the whole thing to a single new list
aslist = list(normalized_list(l))

# verify results
assert aslist == l2

Upvotes: 1

the wolf
the wolf

Reputation: 35522

You can use ast:

>>> import ast
>>> l = [["('N', '', 'SHOWERS', '', 'RD', '11734', '11734', '', '')", "('61060', '61060')"], ['', '', 'NORA', '', 'RD', '10301', '10999', '10400', '10998', '61089', '61089']]
>>> l2=[e for e in ast.literal_eval(l[0][0])]
>>> l2+=[e for e in ast.literal_eval(l[0][1])]
>>> l2=[l2]
>>> l2.append(l[1])

>>> l2
[['N', '', 'SHOWERS', '', 'RD', '11734', '11734', '', '', '61060', '61060'], ['', '', 'NORA', '', 'RD', '10301', '10999', '10400', '10998', '61089', '61089']]

As you may know, eval has some real security issues. ast is quite safe since it can only produce Python base data structures.

Upvotes: 2

Aaron Lelevier
Aaron Lelevier

Reputation: 20770

I would recommend working with Lists instead of Tuples, and then indexing the lists / sublists / and sublists of list if necessary to achieve what you want.

Another Idea would be to make a Class of the structure that you want. Put methods that slice the list. It appears that you want the first 9 items in a tuple, and the last two in a separate tuple. This would be a good way to separate them out as well.

Upvotes: 0

Marcelo Cantos
Marcelo Cantos

Reputation: 185842

If, and only if, you trust the input, you can eval it:

l2 = eval(l[0][0])

I don't fully understand the structure of the entire input, so I can't help you with looping over all of it.

Upvotes: 1

Related Questions