• R/O
• SSH

## AGPlib: Commit

### Commit MetaInfo

Revision 6357c91a7658c1b18fe6d1026aa580807a4ce616 (tree) 2022-10-26 02:07:31 Antoon Pardon Antoon Pardon

### Log Message

The comm2 iterator

### 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 2 2 # 3 3 # Permission is hereby granted, free of charge, to any person obtaining a 4 4 # copy of this software and associated documentation files (the "Software"),
 @@ -153,3 +153,25 @@ 153 153 if self.next is _INVALID: 154 154 self.next = next(self.iterator) 155 155 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' 3 3 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 @@ 2 2 # pylint: disable=missing-function-docstring,invalid-name,missing-module-docstring 3 3 4 4 from unittest import TestCase, main as unitmain #, skip 5 -from random import shuffle 5 +from random import shuffle, randint 6 6 from itertools import product 7 +from operator import itemgetter 7 8 8 9 #from typing import List 9 10 10 11 # pylint: disable=unused-import 11 12 from AGPlib.iterators import PipeIterator, Apply, Map, concat, SubMap, Select, Discard, Peeker 13 +from AGPlib.iterators import comm2 12 14 # pylint: enable=unused-import 13 15 14 16 SIZE_LIMIT = 101
 @@ -46,6 +48,11 @@ 46 48 for sub_iterable in iterable: 47 49 yield from sub_iterable 48 50 51 +def rndrange(*args): 52 + for i in range(*args): 53 + if randint(0, 1) == 1: 54 + yield i 55 + 49 56 # pylint: disable=no-self-argument 50 57 51 58 List = Apply(list)
 @@ -150,4 +157,37 @@ 150 157 peeked = peeker.peek() 151 158 s.assertEqual(index + 1, size) 152 159 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 + 153 193 unitmain()