简体   繁体   中英

Python List of Strings to Tuple Pairs

I am having some difficulty coming up with an efficient way of taking a list of strings and converting it to tuple pairs. I have a list similar to:

listOfNames = ['red-l','blue-l','green-s','red-s','blue-s']

Every color in this example (red, blue, and green) has either a '-l' or '-s' entry or both. I need to convert this list of strings into tuple pairs such as:

tupleOfNames = [('red-l','red-s'),(None,'green-s'),('blue-l','blue-s')]

I think regular expressions is needed but I am not sure how to do so. Any help is greatly appreciated. Thanks

A possible solution, We can sort the list firstly and then groupby the color part of each term and transform each group into a tuple, if it contains only one element insert a None in the tuple:

import re
from itertools import groupby

li = []
listOfNames.sort()
for k, g in groupby(listOfNames, lambda s: re.findall("(.*)-", s)):
    liG = list(g)
    if len(liG) == 1:
        li.append((None, liG[0]))
    else:
        li.append(tuple(liG))

li
# [('blue-l', 'blue-s'), (None, 'green-s'), ('red-l', 'red-s')]

I wrote this function which is far from perfect, but delivers the result you wish for:

  def tupleofnames(listofnames):
        result = []
        colors = set([x[:-2] for x in listOfNames])    
        for c in colors:         
            if c+"-l" in listofnames:
                if c+'-s' in listofnames:
                    result.append((c+"-l",c+'-s'))
                else: 
                    result.append((c+"-l",None))
            else:
                result.append((None,c+"-s"))
        return result

Result looks like:

[(None, 'green-s'), ('red-l', 'red-s'), ('blue-l', 'blue-s')]
listOfNames = ['red-l','blue-l','green-s','red-s','blue-s']
l_list = [a[:-2] for a in filter(lambda x:x[-1]=='l',listOfNames)]
s_list = [a[:-2] for a in filter(lambda x:x[-1]=='s',listOfNames)]
s = {a[:-2] for a in listOfNames}
tuplesOfNames = [tuple([c+'-l' if c in l_list else None,c+'-s' if c in s_list else None]) for c in s]

Output:

[('blue-l', 'blue-s'), ('red-l', 'red-s'), (None, 'green-s')]

This will be slightly faster than alternatives due to spliting into 2 separate lists for elements, so that lookup is bit faster.

I think a nice (and perhaps better) solution is:

from collections import defaultdict
d = defaultdict(list)
listOfNames = ['red-l','blue-l','green-s','red-s','blue-s']
# Go over the list and remember for each color the entry 
for s in listOfNames:
   d[s[:-2]].append(s[-1])
# Go over the colors and produce the appropriate tuple
[ (key+'-l' if 'l' in d[key] else None, key+'-s' if 's' in d[key] else None) for key in d.keys() ]

That outputs:

[('blue-l', 'blue-s'), ('red-l', 'red-s'), (None, 'green-s')]

With that method you go just one time over the original list and one time over the color keys (which is smaller).

The access to the dictionary is O(1) on average so thats should work fast enough.

Check out the itertools.product() function. This returns the cartesian product of two lists. In your case you could do,

from itertools import product

l_names = ['red-l', 'blue-l']
s_names = ['red-s', 'blue-s', 'green-s']

tupleOfNames = list(product(l_names, s_names))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM