Coverage for src/extratools_core/itertools.py: 0%

44 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-05 23:54 -0700

1from collections.abc import Callable, Iterable, Sequence 

2from itertools import chain, count, repeat 

3from typing import Iterator, cast 

4 

5from toolz.itertoolz import sliding_window 

6 

7from .seq import iter_to_seq 

8 

9 

10def iter_to_grams[T]( 

11 _iter: Iterable[T], 

12 *, 

13 n: int, 

14 pad: T | None = None, 

15) -> Iterable[Sequence[T]]: 

16 if pad is not None: 

17 _iter = chain( 

18 repeat(pad, n - 1), 

19 _iter, 

20 repeat(pad, n - 1), 

21 ) 

22 

23 return sliding_window(n, _iter) 

24 

25 

26def filter_by_positions[T](poss: Iterable[int], seq: Iterable[T]) -> Iterable[T]: 

27 p: Iterator[int] = iter(poss) 

28 

29 pos: int | None = next(p, None) 

30 if pos is None: 

31 return 

32 

33 for i, v in enumerate(seq): 

34 if i == pos: 

35 yield v 

36 

37 pos = next(p, None) 

38 if pos is None: 

39 return 

40 

41 

42def filter_by_others[T](func: Callable[[T, T], bool], _iter: Iterable[T]) -> Iterable[T]: 

43 seq: Sequence[T] = iter_to_seq(_iter) 

44 

45 filtered_ids: set[int] = set(range(len(seq))) 

46 

47 for i, x in enumerate(seq): 

48 remove: bool = False 

49 for j in filtered_ids: 

50 if i == j: 

51 continue 

52 

53 if not func(x, seq[j]): 

54 remove = True 

55 break 

56 

57 if remove: 

58 filtered_ids.remove(i) 

59 

60 for i in filtered_ids: 

61 yield seq[i] 

62 

63 

64def remap[KT, VT]( 

65 data: Iterable[KT], 

66 mapping: dict[KT, VT], 

67 *, 

68 key: Callable[[KT], VT] | None = None, 

69) -> Iterable[VT]: 

70 local_key: Callable[[KT], VT] 

71 if key is None: 

72 c = count(start=0) 

73 

74 def default_key(_: KT) -> VT: 

75 return cast("VT", next(c)) 

76 

77 local_key = default_key 

78 else: 

79 local_key = key 

80 

81 k: KT 

82 for k in data: 

83 yield mapping.setdefault(k, local_key(k))