Hướng dẫn python itertools groupby multiple keys - python itertools nhóm theo nhiều phím

Chỉ để mở rộng một chút về câu trả lời được chấp nhận:

Khi bạn sử dụng bộ tuple làm khóa nhóm, bạn có thể truy xuất các giá trị tuple khi lặp lại dữ liệu được nhóm, trong trường hợp bạn cần, ví dụ:

from itertools import groupby

data = [
    {"device_id": 1, "port_id": 1, "some_value": 1},
    {"device_id": 1, "port_id": 2, "some_value": 2},
    {"device_id": 1, "port_id": 2, "some_value": 3},
    {"device_id": 2, "port_id": 1, "some_value": 1},
    {"device_id": 2, "port_id": 1, "some_value": 2},
    {"device_id": 3, "port_id": 1, "some_value": 1},
]

grouped_data = groupby(data, key=lambda x: (x["device_id"], x["port_id"]))

for (device_id, port_id), group in grouped_data:
    print(f"device_id, port_id: {device_id}, {port_id}")
    print(f"  -> group: {list(group)}")

cái nào sẽ in:

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]

Trong Python, bạn có thể nhóm các yếu tố liên tiếp có cùng giá trị trong một đối tượng có thể lặp lại như danh sách với

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
5.

  • itertools.groupby () - Các chức năng tạo trình lặp lại cho vòng lặp hiệu quả - Python 3.10.4 Tài liệu

import itertools

l = [0, 0, 0, 1, 1, 2, 0, 0]
print([(k, list(g)) for k, g in itertools.groupby(l)])
# [(0, [0, 0, 0]), (1, [1, 1]), (2, [2]), (0, [0, 0])]

Bài viết này mô tả các nội dung sau đây.

  • Cách sử dụng
    device_id, port_id: 1, 1
      -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
    device_id, port_id: 1, 2
      -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
    device_id, port_id: 2, 1
      -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
    device_id, port_id: 3, 1
      -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
    
    5
  • Chỉ định chức năng tính toán giá trị khóa cho từng phần tử:
    device_id, port_id: 1, 1
      -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
    device_id, port_id: 1, 2
      -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
    device_id, port_id: 2, 1
      -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
    device_id, port_id: 3, 1
      -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
    
    7
  • Tổng hợp như
    device_id, port_id: 1, 1
      -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
    device_id, port_id: 1, 2
      -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
    device_id, port_id: 2, 1
      -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
    device_id, port_id: 3, 1
      -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
    
    8 trong SQL
  • Đối với bộ dữ liệu và dây

Bạn có thể sử dụng

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
5 để xử lý không chỉ danh sách mà còn cả bộ dữ liệu, chuỗi, v.v.

  • Cho các bộ dữ liệu:

Sử dụng

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
5 nếu bạn muốn tạo một nhóm thành một danh sách.

l = [0, 0, 0, 1, 1, 2, 0, 0]
print(itertools.groupby(l))
# <itertools.groupby object at 0x110ab58b0>

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
2

Cho chuỗi:

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]

Sử dụng

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
6 nếu bạn muốn biến một nhóm thành một chuỗi.

  • Liệt kê sự hiểu biết trong Python

Lưu ý rằng Pandas cũng có

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
3 để nhóm và tổng hợp. Pandas thuận tiện hơn để xử lý dữ liệu phức tạp.

Chỉ định chức năng tính toán giá trị khóa cho từng phần tử: device_id, port_id: 1, 1 -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}] device_id, port_id: 1, 2 -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}] device_id, port_id: 2, 1 -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}] device_id, port_id: 3, 1 -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}] 7

Sử dụng

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
9 để đếm số lượng các yếu tố của cùng một giá trị, bất kể thứ tự của chúng, tức là, liên tiếp hoặc không liên tiếp.

  • Đếm các yếu tố trong một danh sách với bộ sưu tập.

Dựa trên kết quả của hàm (đối tượng có thể gọi) được chỉ định trong

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
7, nó được xác định nếu các giá trị của các phần tử liên tiếp là như nhau.

Ví dụ: nếu bạn chỉ định hàm tích hợp

l = [0, 0, 0, 1, 1, 2, 0, 0]
print(itertools.groupby(l))
# <itertools.groupby object at 0x110ab58b0>
1, trả về độ dài (số lượng ký tự) của chuỗi, các phần tử có cùng độ dài được nhóm lại. Điểm dừng
l = [0, 0, 0, 1, 1, 2, 0, 0]
print(itertools.groupby(l))
# <itertools.groupby object at 0x110ab58b0>
2 là không cần thiết khi chỉ định
device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
7.

l = ['aaa', 'bbb', 'ccc', 'a', 'b', 'aa', 'bb']
print([(k, list(g)) for k, g in itertools.groupby(l, len)])
# [(3, ['aaa', 'bbb', 'ccc']), (1, ['a', 'b']), (2, ['aa', 'bb'])]

Xác định xem số chẵn hay số lẻ với biểu thức Lambda:

  • Biểu cảm lambda trong python

l = [0, 2, 0, 3, 1, 4, 4, 0]
print([(k, list(g)) for k, g in itertools.groupby(l, lambda x: x % 2)])
# [(0, [0, 2, 0]), (1, [3, 1]), (0, [4, 4, 0])]

Tổng hợp như device_id, port_id: 1, 1 -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}] device_id, port_id: 1, 2 -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}] device_id, port_id: 2, 1 -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}] device_id, port_id: 3, 1 -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}] 8 trong SQL

Bạn có thể nhóm dữ liệu hai chiều (chẳng hạn như danh sách danh sách) dựa trên một cột nhất định, như

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
8 trong SQL, với
device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
7.

Ở đây, một biểu thức lambda được sử dụng để có được phần tử ở vị trí mong muốn trong danh sách, nhưng

l = [0, 0, 0, 1, 1, 2, 0, 0]
print(itertools.groupby(l))
# <itertools.groupby object at 0x110ab58b0>
7 cũng có thể được sử dụng.

  • Toán tử.Itemgetter () - Các toán tử tiêu chuẩn là chức năng - Python 3.10.4 Tài liệu

Ngoài ra, câu lệnh

l = [0, 0, 0, 1, 1, 2, 0, 0]
print(itertools.groupby(l))
# <itertools.groupby object at 0x110ab58b0>
8 được sử dụng để làm cho đầu ra dễ đọc hơn, nhưng tất nhiên, bạn cũng có thể sử dụng các toàn bộ danh sách như trong các ví dụ trước.

l = [[0, 'Alice', 0],
     [1, 'Alice', 10],
     [2, 'Bob', 20],
     [3, 'Bob', 30],
     [4, 'Alice', 40]]

for k, g in itertools.groupby(l, lambda x: x[1]):
    print(k, list(g))
# Alice [[0, 'Alice', 0], [1, 'Alice', 10]]
# Bob [[2, 'Bob', 20], [3, 'Bob', 30]]
# Alice [[4, 'Alice', 40]]

Với

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
5, chỉ các yếu tố liên tiếp của cùng một giá trị được nhóm lại.Để nhóm chúng bất kể đặt hàng, hãy sắp xếp danh sách ban đầu với
import itertools

l = [0, 0, 0, 1, 1, 2, 0, 0]
print([(k, list(g)) for k, g in itertools.groupby(l)])
# [(0, [0, 0, 0]), (1, [1, 1]), (2, [2]), (0, [0, 0])]
7.

Khi sắp xếp một danh sách các danh sách, theo mặc định, danh sách được sắp xếp theo phần tử đầu tiên của mỗi danh sách.Để sắp xếp theo phần tử tại vị trí đã cho, chỉ định tham số

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
7 của
import itertools

l = [0, 0, 0, 1, 1, 2, 0, 0]
print([(k, list(g)) for k, g in itertools.groupby(l)])
# [(0, [0, 0, 0]), (1, [1, 1]), (2, [2]), (0, [0, 0])]
7.

for k, g in itertools.groupby(sorted(l, key=lambda x: x[1]), lambda x: x[1]):
    print(k, list(g))
# Alice [[0, 'Alice', 0], [1, 'Alice', 10], [4, 'Alice', 40]]
# Bob [[2, 'Bob', 20], [3, 'Bob', 30]]

Tổng hợp các số bằng biểu thức máy phát:

  • Liệt kê sự hiểu biết trong Python

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
0

Lưu ý rằng Pandas cũng có

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
3 để nhóm và tổng hợp.Pandas thuận tiện hơn để xử lý dữ liệu phức tạp.

  • Pandas.DataFrame.groupby - Pandas 1.4.2 Tài liệu

Đối với bộ dữ liệu và dây

Bạn có thể sử dụng

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
5 để xử lý không chỉ danh sách mà còn cả bộ dữ liệu, chuỗi, v.v.

Cho các bộ dữ liệu:

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
1

Sử dụng

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
5 nếu bạn muốn tạo một nhóm thành một danh sách.

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
2

Cho chuỗi:

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
3

Sử dụng

for k, g in itertools.groupby(l):
    print(k, g)
# 0 <itertools._grouper object at 0x110a26940>
# 1 <itertools._grouper object at 0x110a2c400>
# 2 <itertools._grouper object at 0x110aa8f10>
# 0 <itertools._grouper object at 0x110aa8ee0>

for k, g in itertools.groupby(l):
    print(k, list(g))
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2]
# 0 [0, 0]
6 nếu bạn muốn biến một nhóm thành một chuỗi.

  • Chuỗi Concatenate trong Python (+ toán tử, tham gia, v.v.)

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
4

Tất nhiên, bạn cũng có thể xử lý bất kỳ đối tượng có thể lặp lại nào khác với

device_id, port_id: 1, 1
  -> group: [{'device_id': 1, 'port_id': 1, 'some_value': 1}]
device_id, port_id: 1, 2
  -> group: [{'device_id': 1, 'port_id': 2, 'some_value': 2}, {'device_id': 1, 'port_id': 2, 'some_value': 3}]
device_id, port_id: 2, 1
  -> group: [{'device_id': 2, 'port_id': 1, 'some_value': 1}, {'device_id': 2, 'port_id': 1, 'some_value': 2}]
device_id, port_id: 3, 1
  -> group: [{'device_id': 3, 'port_id': 1, 'some_value': 1}]
5.