Commit MetaInfo

Revision6357c91a7658c1b18fe6d1026aa580807a4ce616 (tree)
Time2022-10-26 02:07:31
AuthorAntoon Pardon <aej@pard...>
CommiterAntoon Pardon

Log Message

The comm2 iterator

Change Summary

Incremental Difference

diff -r a1f21f973dad -r 6357c91a7658 source/iterators.py
--- a/source/iterators.py Thu Sep 15 20:45:47 2022 +0200
+++ b/source/iterators.py Tue Oct 25 19:07:31 2022 +0200
@@ -1,4 +1,4 @@
1-# Copyright © 2017-2019 Antoon Pardon
1+# Copyright © 2017-2022 Antoon Pardon
22 #
33 # Permission is hereby granted, free of charge, to any person obtaining a
44 # copy of this software and associated documentation files (the "Software"),
@@ -153,3 +153,25 @@
153153 if self.next is _INVALID:
154154 self.next = next(self.iterator)
155155 return self.next
156+
157+def comm2(it1: Iterable[Any], it2: Iterable[Any]) -> Iterable[tuple[Any, Any]]:
158+ """
159+ This function behave a bit like the unix command comm.
160+ It takes two sorted iterators and produces an iterator of tuples.
161+ """
162+ top = 1,None
163+ it1 = ((0, item) for item in it1)
164+ it2 = ((0, item) for item in it2)
165+ item1 = next(it1, top)
166+ item2 = next(it2, top)
167+ while (item1, item2) != (top, top):
168+ if item1 < item2:
169+ yield item1[1], None
170+ item1 = next(it1, top)
171+ elif item1 > item2:
172+ yield None, item2[1]
173+ item2 = next(it2, top)
174+ else:
175+ yield item1[1], item2[1]
176+ item1 = next(it1, top)
177+ item2 = next(it2, top)
diff -r a1f21f973dad -r 6357c91a7658 source/release.cfg
--- a/source/release.cfg Thu Sep 15 20:45:47 2022 +0200
+++ b/source/release.cfg Tue Oct 25 19:07:31 2022 +0200
@@ -1,3 +1,3 @@
1-version = '0.01.12k'
2-modified = '2022-09-12 @ 13:20:16'
1+version = '0.01.13g'
2+modified = '2022-10-25 @ 19:07:31'
33 installed = '*********************'
diff -r a1f21f973dad -r 6357c91a7658 tests/iterators.py
--- a/tests/iterators.py Thu Sep 15 20:45:47 2022 +0200
+++ b/tests/iterators.py Tue Oct 25 19:07:31 2022 +0200
@@ -2,13 +2,15 @@
22 # pylint: disable=missing-function-docstring,invalid-name,missing-module-docstring
33
44 from unittest import TestCase, main as unitmain #, skip
5-from random import shuffle
5+from random import shuffle, randint
66 from itertools import product
7+from operator import itemgetter
78
89 #from typing import List
910
1011 # pylint: disable=unused-import
1112 from AGPlib.iterators import PipeIterator, Apply, Map, concat, SubMap, Select, Discard, Peeker
13+from AGPlib.iterators import comm2
1214 # pylint: enable=unused-import
1315
1416 SIZE_LIMIT = 101
@@ -46,6 +48,11 @@
4648 for sub_iterable in iterable:
4749 yield from sub_iterable
4850
51+def rndrange(*args):
52+ for i in range(*args):
53+ if randint(0, 1) == 1:
54+ yield i
55+
4956 # pylint: disable=no-self-argument
5057
5158 List = Apply(list)
@@ -150,4 +157,37 @@
150157 peeked = peeker.peek()
151158 s.assertEqual(index + 1, size)
152159
160+ def test_comm2_double_empty(s):
161+ comm_lst = list(comm2([], []))
162+ s.assertEqual(comm_lst, [])
163+
164+ def test_comm2_one_empty(s):
165+ lst = list(rndrange(200))
166+ length = len(lst)
167+ Nones = length * [None]
168+ comm_lst1 = list(comm2(lst, []))
169+ projected0 = list(map(itemgetter(0), comm_lst1))
170+ projected1 = list(map(itemgetter(1), comm_lst1))
171+ s.assertEqual(lst, projected0)
172+ s.assertEqual(Nones, projected1)
173+ comm_lst2 = list(comm2([], lst))
174+ projected0 = list(map(itemgetter(0), comm_lst2))
175+ projected1 = list(map(itemgetter(1), comm_lst2))
176+ s.assertEqual(Nones, projected0)
177+ s.assertEqual(lst, projected1)
178+
179+ def test_comm2_double_filled(s):
180+ itr1 = rndrange(1, 4096)
181+ itr2 = rndrange(1, 4096)
182+ prv = 0
183+ for item in comm2(itr1, itr2):
184+ if item[0] is None:
185+ nxt = item[1]
186+ elif item[1] is None:
187+ nxt = item[0]
188+ else:
189+ s.assertEqual(*item)
190+ nxt = item[1]
191+ s.assertLess(prv, nxt)
192+
153193 unitmain()
Show on old repository browser