Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
group by property
#1
I have a list like:
result = [
  {
    "name: "John",
    "m": "good",
    "n": 1
  },
  {
    "name": 'Alina',
    "m": "good",
    "n": 1
  },
  {
    "name": "Olivia",
    "m": "bad",
    "n": 2
  },
  {
    "name": "Ruby",
    "m": "bad",
    "n": 2
  },
  ...
]
I want to convert it into like this:
result = [
  { // n is 1
    "g": [
      {
        "name": "John",
        "n": 1
      },
      {
        "name":"Alina",
        "n": 1
      }
    ],
    "b": [
      {
        "name": "...",
        "n": 1
      },
      {
        "name": "...",
        "n": 1
      }
    ]
  },
  { // n is 2
    "g": [...],
    "b": [...]
  },
  { // n is 3
   // ...
  }
]
What I'm trying to achieve here is as follows:
- if m is good, g should have group of dictionary where n matches
- if m is bad, b should have group of dictionary where n matches

So, here I have to group them by n and with good and bad property. Hope this is clear.

Please note the value of n is generated with timestamp. I have shown here 1,2,3.. just for ease.
Reply
#2
Here, this should do the trick. List represents result and NewList is the actual result
List = [
  {
    "name": "John",
    "m": "good",
    "n": 1
  },
  {
    "name": 'Alina',
    "m": "good",
    "n": 1
  },
  {
    "name": "Olivia",
    "m": "bad",
    "n": 2
  },
  {
    "name": "Ruby",
    "m": "bad",
    "n": 2
  }
]

NewList = [{'g' : [], 'b' : []}]
for Dict in List:
    if Dict['n'] == len(NewList):
        NewList[Dict['n'] - 1][Dict['m'][0]].append(Dict)
    else:
        NewList.append({'g' : [], 'b' : []})
print(NewList)
Reply
#3
Thanks. It is grouping as expected. But it is returning empty [].

[
  {
    "g": [],
    "b": []
  },
  {
    "g": [],
    "b": []
  },
  ...
]
Probably this line is issue:
NewList[Dict['n'] - 1][Dict['m'][0]].append(Dict)
You are probably decreasing n value. I have random number rather than increasing number. So, I have to match the n exactly not by decreasing.
Reply
#4
No, the first empty is for bad with number 1. But there are no bad with number 1. Therefore it leaves it empty. The next empty one is for good with number 2 but there are no good with number 2
Reply
#5
I have all the matching data with n, good, bad. The logic I think is not matching n with other n data.
Reply
#6
Try this and you get no empty spaces because each number has a good and a bad.
List = [
  {
    "name": "John",
    "m": "good",
    "n": 1
  },
  {
    "name": 'Alina',
    "m": "good",
    "n": 1
  },
  {
    "name": "Peter",
    "m": "bad",
    "n": 1
  },
  {
    "name": 'Mary',
    "m": "bad",
    "n": 1
  },
  {
    "name": "Olivia",
    "m": "bad",
    "n": 2
  },
  {
    "name": "Ruby",
    "m": "bad",
    "n": 2
  },
  {
    "name": "Sukuyomi",
    "m": "good",
    "n": 2
  },
  {
    "name": "Furuhashi",
    "m": "good",
    "n": 2
  }
]

NewList = [{'g' : [], 'b' : []}]
for Dict in List:
    if Dict['n'] == len(NewList):
        NewList[Dict['n'] - 1][Dict['m'][0]].append(Dict)
    else:
        NewList.append({'g' : [], 'b' : []})
print(NewList)
Reply
#7
Pandas is a very good tool to perform grouping, e.g.

import pandas as pd
df = pd.DataFrame(data)
df.groupby(['m', 'n']).groups
Output:
{('bad', 2): Int64Index([2, 3], dtype='int64'), ('bad', 3): Int64Index([4], dtype='int64'), ('good', 1): Int64Index([0, 1], dtype='int64')}
If you don't want to use Pandas, you can do this using standard Python packages only, e.g.

from itertools import groupby
from operator import itemgetter
for a, b in groupby(data, key=lambda x: (itemgetter('m')(x), itemgetter('n')(x))):
    print(a, list(b))
Output:
('good', 1) [{'name': 'John', 'm': 'good', 'n': 1}, {'name': 'Alina', 'm': 'good', 'n': 1}] ('bad', 2) [{'name': 'Olivia', 'm': 'bad', 'n': 2}, {'name': 'Ruby', 'm': 'bad', 'n': 2}] ('bad', 3) [{'name': 'Ruby', 'm': 'bad', 'n': 3}]
This might be not exactly you want. Nevertheless, these approaches may be useful: you can easily access/process the data in each group.
Reply
#8
As I said the value of n is generated with timestamp. So it doesn't work. Try the following which results empty list:

List = [
    {
      "name": "John",
      "m": "good",
      "n": 1561895746657
    },
    {
      "name": 'Alina',
      "m": "good",
      "n": 1561895746657
    },
    {
      "name": "Peter",
      "m": "bad",
      "n": 1561895746657
    },
    {
      "name": 'Mary',
      "m": "bad",
      "n": 1561895746657
    },
    {
      "name": "Olivia",
      "m": "bad",
      "n": 1561872416143
    },
    {
      "name": "Ruby",
      "m": "bad",
      "n": 1561872416143
    },
    {
      "name": "Sukuyomi",
      "m": "good",
      "n": 1561872416143
    },
    {
      "name": "Furuhashi",
      "m": "good",
      "n": 1561872416143
    }
  ]
  
  NewList = [{'g' : [], 'b' : []}]
  for Dict in List:
      if Dict['n'] == len(NewList):
          NewList[Dict['n'] - 1][Dict['m'][0]].append(Dict)
      else:
          NewList.append({'g' : [], 'b' : []})
  print(NewList)

@scidam,

I just tried with standard library. And it works fine. But I'm not sure if I understand them.

@SheeppOSU,

I would love to use your method coz, I don't need to import other library. So, can you please update your answer once again with the given timestamp?
Reply
#9
I just tested it and it worked for me, so hope it works for you
NewList = []
for Dict in List:
    if not NewList:
        NewList.append({'n' : Dict['n'], 'g' : [], 'b' : []})
    new = False
    count = 0
    for SortedDict in NewList:
        if SortedDict['n'] == Dict['n']:
            new = False
            NewList[count][Dict['m'][0]].append(Dict)
            break
        else:
            new = True
        count += 1
    if new:
        NewList.append({'n' : Dict['n'], 'g' : [], 'b' : []})
        NewList[len(NewList) - 1][Dict['m'][0]].append(Dict)
print(NewList)
Reply
#10
Not sure where I'm gone wrong. But I'm getting KeyError 'c'. I couldn't see anywhere using 'c' as key.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Subclass initialized property used in parent class method. Is it bad coding practice? saavedra29 5 1,685 Feb-07-2022, 07:29 PM
Last Post: saavedra29
  ABC Module and @property decorator, Pythonic Way? muzikman 21 5,496 Aug-18-2021, 06:08 PM
Last Post: muzikman
  @property vs __set__ / __get__ and __setattr__ / __getattr__ okhajut 1 3,255 Jun-15-2021, 03:48 PM
Last Post: snippsat
  Can property getters and setters have additional arguments? pjfarley3 2 2,992 Oct-30-2020, 12:17 AM
Last Post: pjfarley3
  Property price calculation oli_action 4 3,091 Jul-15-2020, 04:27 PM
Last Post: sridhar
  Use of @property decorator ruy 16 6,378 Jun-09-2020, 05:29 PM
Last Post: buran
  Problem adding keys/values to dictionary where keynames = "property" and "value" jasonashaw 1 2,018 Dec-17-2019, 08:00 PM
Last Post: jasonashaw
  strange class property KaliLinux 2 2,312 Nov-25-2019, 04:32 PM
Last Post: KaliLinux
  print all method and property of list object engmoh 4 2,801 Oct-26-2019, 05:33 PM
Last Post: engmoh
  what is the doc parameter of property? microphone_head 2 2,444 Apr-11-2019, 08:59 AM
Last Post: microphone_head

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020