0

I have a list which contains a simple object of a class, say Person i.e:

my_list [Person<obj>, Person<obj> ..]

This Person object is very simple, has various variables, values i.e:

Person_n.name = 'Philip'
Person_n.height = '180'
Person_n.lives_in = 'apartment' 

So as you can see, all these Persons live somewhere whether: apartment, house or boat.

What I want to create is a new list, or a dictionary (does not matter which) in which I have this list sorted in a way that they are grouped by their lives_in values and the most populated choice is the number one in the new list (or dictionary, in which lives_in value would be the key).

E.g.:

new_list = [('apartment', [Person_1, Person_5, Person_6, Person_4]), ('house': [Person_2, Peson_7]), ('boat': [Person_3])]

I am new to Python and I am stuck with endless loops. There must be a simple way to do this without looping through 4 times.

What is the Pythonic way to achieve this desired new list?

Phil
  • 13,875
  • 21
  • 81
  • 126
  • 2
    Two steps: `sorted` to sort the list, and then `itertools.groupby` to group them by a key. Try with those two, and then update the question if you run into an issue. See the answer to [this question](http://stackoverflow.com/questions/13096955/finding-similar-data-and-putting-them-on-seperate-list) for more information. – Burhan Khalid Oct 27 '12 at 04:21
  • 1
    As a side note: it's usually a good idea to write a `__repr__` or a `__str__` for your classes so that you can see something meaningful when you put instances of you class into a list – inspectorG4dget Oct 27 '12 at 04:32
  • @inspectorG4dget To nitpick, you shouldn't change `__repr__` for readability purpose, but only change `__str__`. See: http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python – K Z Oct 27 '12 at 04:51
  • 1
    To continue: `__repr__` should always return a representation that can be evaluated to get the original object, which may not necessarily be human readable. `__str__` though, is for human readability purpose. – K Z Oct 27 '12 at 04:56
  • Burhan, Mr. Inspector, Kay and Kay, I thank all three of you for your help. All this information is very valuable and from a tiny question I learnt a lot more essentials. Thanks a lot! – Phil Oct 27 '12 at 13:29

3 Answers3

7

You need to sort it first before passing it to groupby:

sorted_list = sorted(my_list, key=lambda x: x.lives_in)

then use itertools.groupby:

from itertools import groupby

groupby(sorted_list, key=lambda x: x.lives_in)
result = [(key, list(group)) \
        for key, group in groupby(sorted_list, key=lambda x: x.lives_in)]
K Z
  • 29,661
  • 8
  • 73
  • 78
  • Thank you @KayZhu for this answer and the explanation. I just have one more question to make things more complex. Say no matter how many items it contains, I want a certain group to be always last in the new ordered list. What would I do then besides looking for it's key, popping it and appending it to end? – Phil Oct 27 '12 at 13:47
  • By the way, I just realised, unless I am doing something wrong, this do not sort the groups by their population? – Phil Oct 27 '12 at 14:07
  • @Phil second question first: each group contains all the `Person`s who has the same `lives_in` attribute, and it is sorted by the alphabetical order of `lives_in` – K Z Oct 27 '12 at 20:32
  • @Phil first question, yes I think the easiest is just to pop it then append it to the end again – K Z Oct 27 '12 at 20:33
  • @Phil if you want to sort the groups by their population (the number of people who live in the same place), you can use `sorted_result = sorted(result, key=lambda x:len(x[1]))` – K Z Oct 27 '12 at 22:25
  • thank you very much for your help. I wish there was a better way other than sorting 3 times but I guess that's life. ;-) – Phil Oct 27 '12 at 22:56
  • @Phil glad to help :) and just to be clear, it is actually only sorting twice, groupby doesn't really sort it, only to group it by key :) – K Z Oct 27 '12 at 23:01
3
people = my_list_of_people
people.sort(key=operator.attrgetter('lives_in')) # sort the people by where they live
groups = itertools.groupby(people, key=operator.attrgetter('lives_in')) # group the sorted people by where they live
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
2

Suppose your Person list is in myList and you want to create newList. I'm kind of new to stack overflow so I'm not using tabs. Can someone help me out lol. But here's the code:

for i in xrange(len(myList)):
     found = false;
     for j in xrange(len(newList)):
          if newList[j][0]==myList[i].lives_in:
                found = true;
                 newList[j][1].append(myList[i]);
     if !found:
          newList.append((myList[i].lives_in, [myList[i]]))
Math is Hard
  • 896
  • 1
  • 12
  • 24