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

52 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-06 00:04 -0700

1from collections.abc import Callable, Iterable, Iterator, Sequence 

2from itertools import chain, count, repeat 

3from typing import cast 

4 

5from toolz.itertoolz import sliding_window 

6 

7from .seq import iter_to_seq 

8from .typing import Comparable 

9 

10 

11def iter_to_grams[T]( 

12 _iter: Iterable[T], 

13 *, 

14 n: int, 

15 pad: T | None = None, 

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

17 if pad is not None: 

18 _iter = chain( 

19 repeat(pad, n - 1), 

20 _iter, 

21 repeat(pad, n - 1), 

22 ) 

23 

24 return sliding_window(n, _iter) 

25 

26 

27def is_sorted[T]( 

28 seq: Iterable[T], 

29 *, 

30 key: Callable[[T], Comparable] | None = None, 

31 reverse: bool = False, 

32) -> bool: 

33 local_key: Callable[[T], Comparable] 

34 if key is None: 

35 def default_key(v: T) -> Comparable: 

36 return cast("Comparable", v) 

37 

38 local_key = default_key 

39 else: 

40 local_key = key 

41 

42 return all( 

43 ( 

44 local_key(prev) >= local_key(curr) if reverse 

45 else local_key(prev) <= local_key(curr) 

46 ) 

47 for prev, curr in sliding_window(2, seq) 

48 ) 

49 

50 

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

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

53 

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

55 if pos is None: 

56 return 

57 

58 for i, v in enumerate(seq): 

59 if i == pos: 

60 yield v 

61 

62 pos = next(p, None) 

63 if pos is None: 

64 return 

65 

66 

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

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

69 

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

71 

72 for i, x in enumerate(seq): 

73 remove: bool = False 

74 for j in filtered_ids: 

75 if i == j: 

76 continue 

77 

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

79 remove = True 

80 break 

81 

82 if remove: 

83 filtered_ids.remove(i) 

84 

85 for i in filtered_ids: 

86 yield seq[i] 

87 

88 

89def remap[KT, VT]( 

90 data: Iterable[KT], 

91 mapping: dict[KT, VT], 

92 *, 

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

94) -> Iterable[VT]: 

95 local_key: Callable[[KT], VT] 

96 if key is None: 

97 c = count(start=0) 

98 

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

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

101 

102 local_key = default_key 

103 else: 

104 local_key = key 

105 

106 k: KT 

107 for k in data: 

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