0

I have a list of tuples that consist of objects of a certain class and differ in their dimension:

my_list = [(obj1, obj2), (obj3, obj1), (obj4, obj1), (obj2,),...]

All of these objects have an attribute label which is of type string and holds an object label e.g. 'object_1', 'object_2' and so on.

Now I want to extract the string representation of the tuples holding the attribute values (labels) e.g.:

my_new_list = ['(object_1, object_2)', '(object_3, object_1)', '(object_4, object_1)', '(object_2,)', ...]

I have looked up how to extract a list of attributes from a list of objects and how to convert a tuple to string and would probably achieve my goal with some nested for loops. But I got stuck in some messy code here..

But isn't there some nice pythonic way to do this?

Thanks in advance!

*EDIT: Some of the tuples are one dimensional e.g. (obj2,). Sorry, I forgot that and now have adapted my question!

Cord Kaldemeyer
  • 6,405
  • 8
  • 51
  • 81
  • What's wrong with a standard list comprehension here? – alkasm Sep 19 '17 at 09:10
  • It's not the objects only but the attributes within the string representation of the tuples. – Cord Kaldemeyer Sep 19 '17 at 09:17
  • As a general tip you can usually see the structure of the comprehension just by writing it out with actual for loops. In this case you'd write `for obj1, obj2 in my_list` to bring out the tuples, and then append `'(%s,%s)' % (obj1.label, obj2.label)` to an initially empty list. And you can see that same structure in the answers below. Edit: Just saw the edit. Same general principle applies. – alkasm Sep 19 '17 at 09:21
  • Thanks anyway for your tip! – Cord Kaldemeyer Sep 19 '17 at 09:27
  • I added a more general answer not using nested comprehensions that I think reads nicely and is standard python. It's a great practice to give your classes good string representations with a `__repr__` function so they can be used in a manner like this. `print(my_obj)` is just nicer than `print(my_obj.label)` if the label makes sense to be the...well...label of the object. – alkasm Sep 19 '17 at 09:53

5 Answers5

3

You can do

["(%s, %s)" %(i.label, j.label) for i, j in my_list]

If dynamic length inside tuple:

["(%s)" %", ".join([j.label for j in i]) for i in my_list]
itzMEonTV
  • 19,851
  • 4
  • 39
  • 49
1

You can use list comprehension for that:

['({}, {})'.format(el1.label, el2.label) for el1, el2 in my_list]

To not depend from tuple dimension use helper function:

def tuple_print(tup):
    return '({})'.format(', '.join(t.label for t in tup))

my_new_list = [tuple_print(tup) for tup in my_list]
Valdemar
  • 87
  • 3
1

The two other simple list comprehension answers work fine for an arbitrary list of tuples of objects with the attribute. However, Python has some great built-in functionality which let you choose the string representation of your objects, and most built-in types have this already. For example, any tuple can be cast to it's string representation just by encasing the tuple with str(tuple):

>>> str((5, 4))
'(5, 4)'

Now, if you did this with a tuple of arbitrary objects, then you'd get a string which has the actual object handle like <__main__.YourClass object at 0x10ad58fd0> which is ugly. But, if you provide a __repr__ function inside your class definition, then you can change that standard handle to something you like instead. In this case, your label seems like a good candidate to return for the string representation of your object. Here's a minimal example created with your same code:

class LabeledObj:

    def __init__(self, label):
        self.label = label

    def __repr__(self):
        return self.label


obj1 = LabeledObj('object_1')
obj2 = LabeledObj('object_2')
obj3 = LabeledObj('object_3')
obj4 = LabeledObj('object_4')

my_list = [(obj1, obj2), (obj3, obj1), (obj4, obj1), (obj2,)]

my_new_list = [str(obj_tuple) for obj_tuple in my_list]
print(my_new_list)

['(object_1, object_2)', '(object_3, object_1)', '(object_4, object_1)', '(object_2,)']

Now I think this is very pythonic and very clear later in the code, and defining the __repr__ only takes an additional two lines of code. And now you can print(my_obj) instead of print(my_obj.label) which reads nicely.

alkasm
  • 22,094
  • 5
  • 78
  • 94
1

Tuple list elements count using len() + generator expression

temp = list((int(j) for i in test_list for j in i)) 
res = len(temp)
Gau Rav
  • 357
  • 3
  • 13
0

You can use map function to help. This can be complete in one line of code

my_new_list = list(map(lambda P: '({})'.format(','.join(list(map(lambda t:t.label,list(P))))),my_list))

This also work with one dimension tuples.

Amit Darji
  • 457
  • 3
  • 11