الفرق بين المراجعتين لصفحة: «Python/itertools/groupby»
لا ملخص تعديل |
|||
سطر 43: | سطر 43: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
وكما تُلاحظ، فالتّجميع هنا مُتقطّع لأنّ الكائن القابل للتّكرار المُعطى ليس مُرتّبًا. لذا لو رتّبناه بالدّالة sorted() قبل أن نُقسّمه إلى مجموعات فسنحصل على مجموعات أشمل دون تكرار للمفتاح: | وكما تُلاحظ، فالتّجميع هنا مُتقطّع لأنّ الكائن القابل للتّكرار المُعطى ليس مُرتّبًا. لذا لو رتّبناه بالدّالة <code>[[Python/sorted|sorted()]]</code> قبل أن نُقسّمه إلى مجموعات فسنحصل على مجموعات أشمل دون تكرار للمفتاح: | ||
<syntaxhighlight lang="python3"> | <syntaxhighlight lang="python3"> | ||
>>> it = sorted('AAAABBBCCAABBB') | >>> it = sorted('AAAABBBCCAABBB') | ||
سطر 56: | سطر 56: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
يُمكن استعمال المُعامل <code>key</code> لتقسيم قاموس أشخاص إلى مجموعات حسب أعمارهم مثلًا، وذلك عبر استعمال تعبير lambda يستقبل القاموس ويُعيد عمر الشّخص كما يلي: | يُمكن استعمال المُعامل <code>key</code> لتقسيم قاموس أشخاص إلى مجموعات حسب أعمارهم مثلًا، وذلك عبر استعمال [[Python/lambda expressions|تعبير lambda]] يستقبل القاموس ويُعيد عمر الشّخص كما يلي: | ||
<syntaxhighlight lang="python3"> | <syntaxhighlight lang="python3"> | ||
سطر 80: | سطر 80: | ||
27: [{'name': 'Fatima', 'age': 27}] | 27: [{'name': 'Fatima', 'age': 27}] | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== ملاحظات == | == ملاحظات == |
مراجعة 03:30، 13 يونيو 2018
تعيد الدّالة itertools.groupby()
مُكرّرًا يُعيد مفاتيح مُتسلسلة ومجموعات (groups) تنتمي إلى هذه المفاتيح من الكائن القابل للتّكرار المعطى.
العمليّة التي تقوم بها الدّالة مُشابهة لكيفيّة عمل المُرشّح uniq
في أنظمة Unix. إذ تُولّد نقطة توقّف (break) أو مجموعة جديدة في كلّ مرّة تتغيّر فيها قيمة الدّالةِ المفتاح (لذا يجب في الغالب ترتيب البيانات باستعمال نفس الدّالة المفتاح). وطريقة العمل هذه تختلف عن طريقة عمل عبارة GROUP BY
في لغة SQL التي تجمع العناصر المُشتركة بغضّ النّظر عن ترتيب البيانات.
البنية العامة
itertools.groupby(iterable, key=None)
المعاملات
iterable
الكائن القابل للتّكرار المرغوب تجميع عناصره المُشتركة.
key
الدّالة التي تُعيد المفتاح الذي سيُستعمل لتجميع عناصر الكائن القابل للتّكرار لكل عنصر من عناصره. إن لم تُمرَّر للمُعامل أيّة قيمة، أو مُرّرت له القيمة None
، فستكون قيمة المُعامل key
الافتراضيّة عبارة عن دالّة هُويّة (identity function) تُعيد العنصر دون تغيير. يجب على الكائن iterable
أن يكون مُرتّبًا على نفس الدّالة key
.
القيمة المعادة
مُكرّر يحتوي على عدّة صفوف من عنصرين، العنصر الأول يُمثّل المفتاح، والعنصر الثّاني يُمثّل مجموعة القيم المُرتبطة بالمفتاح.
المجموعة المُعادة تكون مُكرّرًا يُشارك الكائن القابل للتّكرار الداخليّ مع الدّالة itertools.groupby()
. ولأنّ المصدر مُشارَك، فستختفي المجموعات كلّما تقدّم الكائن المُعاد (عبر التّكرار). لذا إن كانت البيانات مُهمّة حتى بعد المرور على المجموعات المُعادة، فسيتوجّب عليك تخزينها في قائمة كما يلي:
groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # خزّن مُكرّر المجموعة كقائمة
uniquekeys.append(k)
أمثلة
المثال التّالي يوضّح كيفيّة عمل هذه الدّالة، نستعمل في هذا المثال إحاطات القوائم (List comprehensions) لإنشاء قاموس من المجموعات المُعادة، مفاتيح القاموس تكون هي نفسها المفاتيح التي تُعاد من طرف الدّالة key
(في هذه الحالة العناصر هي نفسها المفاتيح) وتكون قيمة كل مفتاحٍ في القاموس عبارة عن قائمة بالعناصر المتعلّقة بالمفتاح (نحصل على قائمة العناصر بالدّالة list()
):
>>> it = 'AAAABBBCCAABBB'
>>> groups = itertools.groupby(it)
>>> [{key: list(group)} for key, group in groups]
[{'A': ['A', 'A', 'A', 'A']},
{'B': ['B', 'B', 'B']},
{'C': ['C', 'C']},
{'A': ['A', 'A']},
{'B': ['B', 'B', 'B']}]
وكما تُلاحظ، فالتّجميع هنا مُتقطّع لأنّ الكائن القابل للتّكرار المُعطى ليس مُرتّبًا. لذا لو رتّبناه بالدّالة sorted()
قبل أن نُقسّمه إلى مجموعات فسنحصل على مجموعات أشمل دون تكرار للمفتاح:
>>> it = sorted('AAAABBBCCAABBB')
>>> it
['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C']
>>> groups = itertools.groupby(it)
>>> [{key: list(group)} for key, group in groups]
[{'A': ['A', 'A', 'A', 'A', 'A', 'A']},
{'B': ['B', 'B', 'B', 'B', 'B', 'B']},
{'C': ['C', 'C']}
]
يُمكن استعمال المُعامل key
لتقسيم قاموس أشخاص إلى مجموعات حسب أعمارهم مثلًا، وذلك عبر استعمال تعبير lambda يستقبل القاموس ويُعيد عمر الشّخص كما يلي:
>>> people = [{'name': 'Ahmed', 'age': 18},
... {'name': 'Mohamed', 'age': 18},
... {'name': 'Yasser', 'age': 18},
... {'name': 'Yossuf', 'age': 24},
... {'name': 'Fatima', 'age': 27}
... ]
>>> grouped_people = itertools.groupby(people, key=lambda x: x['age'])
>>> for age, group in grouped_people:
... print(f'{age}: {list(group)}')
...
18: [{'name': 'Ahmed', 'age': 18},
{'name': 'Mohamed', 'age': 18},
{'name': 'Yasser', 'age': 18}]
24: [{'name': 'Yossuf', 'age': 24}]
27: [{'name': 'Fatima', 'age': 27}]
ملاحظات
الدّالة مُكافئة لما يلي:
class groupby:
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
def __init__(self, iterable, key=None):
if key is None:
key = lambda x: x
self.keyfunc = key
self.it = iter(iterable)
self.tgtkey = self.currkey = self.currvalue = object()
def __iter__(self):
return self
def __next__(self):
while self.currkey == self.tgtkey:
self.currvalue = next(self.it) # Exit on StopIteration
self.currkey = self.keyfunc(self.currvalue)
self.tgtkey = self.currkey
return (self.currkey, self._grouper(self.tgtkey))
def _grouper(self, tgtkey):
while self.currkey == tgtkey:
yield self.currvalue
try:
self.currvalue = next(self.it)
except StopIteration:
return
self.currkey = self.keyfunc(self.currvalue)