Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/env python 

2# cardinal_pythonlib/lists.py 

3 

4""" 

5=============================================================================== 

6 

7 Original code copyright (C) 2009-2021 Rudolf Cardinal (rudolf@pobox.com). 

8 

9 This file is part of cardinal_pythonlib. 

10 

11 Licensed under the Apache License, Version 2.0 (the "License"); 

12 you may not use this file except in compliance with the License. 

13 You may obtain a copy of the License at 

14 

15 https://www.apache.org/licenses/LICENSE-2.0 

16 

17 Unless required by applicable law or agreed to in writing, software 

18 distributed under the License is distributed on an "AS IS" BASIS, 

19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

20 See the License for the specific language governing permissions and 

21 limitations under the License. 

22 

23=============================================================================== 

24 

25**Functions for dealing with lists.** 

26 

27""" 

28 

29from collections import Counter 

30from operator import itemgetter 

31from typing import Any, Callable, Iterable, List, Tuple 

32 

33 

34# ============================================================================= 

35# Lists and similar 

36# ============================================================================= 

37 

38def contains_duplicates(values: Iterable[Any]) -> bool: 

39 """ 

40 Does the iterable contain any duplicate values? 

41 """ 

42 for v in Counter(values).values(): 

43 if v > 1: 

44 return True 

45 return False 

46 

47 

48def index_list_for_sort_order(x: List[Any], key: Callable[[Any], Any] = None, 

49 reverse: bool = False) -> List[int]: 

50 """ 

51 Returns a list of indexes of ``x``, IF ``x`` WERE TO BE SORTED. 

52 

53 Args: 

54 x: data 

55 key: function to be applied to the data to generate a sort key; this 

56 function is passed as the ``key=`` parameter to :func:`sorted`; 

57 the default is ``itemgetter(1)`` 

58 reverse: reverse the sort order? 

59 

60 Returns: 

61 list of integer index values 

62 

63 Example: 

64 

65 .. code-block:: python 

66 

67 z = ["a", "c", "b"] 

68 index_list_for_sort_order(z) # [0, 2, 1] 

69 index_list_for_sort_order(z, reverse=True) # [1, 2, 0] 

70 q = [("a", 9), ("b", 8), ("c", 7)] 

71 index_list_for_sort_order(q, key=itemgetter(1)) 

72 

73 """ 

74 def key_with_user_func(idx_val: Tuple[int, Any]): 

75 return key(idx_val[1]) 

76 if key: 

77 sort_key = key_with_user_func 

78 # see the simpler version below 

79 else: 

80 sort_key = itemgetter(1) 

81 # enumerate, below, will return tuples of (index, value), so 

82 # itemgetter(1) means sort by the value 

83 index_value_list = sorted(enumerate(x), key=sort_key, reverse=reverse) 

84 return [i for i, _ in index_value_list] 

85 

86 

87def sort_list_by_index_list(x: List[Any], indexes: List[int]) -> None: 

88 """ 

89 Re-orders ``x`` by the list of ``indexes`` of ``x``, in place. 

90 

91 Example: 

92 

93 .. code-block:: python 

94 

95 from cardinal_pythonlib.lists import sort_list_by_index_list 

96 

97 z = ["a", "b", "c", "d", "e"] 

98 sort_list_by_index_list(z, [4, 0, 1, 2, 3]) 

99 z # ["e", "a", "b", "c", "d"] 

100 """ 

101 x[:] = [x[i] for i in indexes] 

102 

103 

104def flatten_list(x: List[Any]) -> List[Any]: 

105 """ 

106 Converts a list of lists into a flat list. 

107  

108 Args: 

109 x: list of lists  

110 

111 Returns: 

112 flat list 

113  

114 As per 

115 https://stackoverflow.com/questions/952914/making-a-flat-list-out-of-list-of-lists-in-python 

116 

117 """ # noqa 

118 return [item for sublist in x for item in sublist] 

119 

120 

121def unique_list(seq: Iterable[Any]) -> List[Any]: 

122 """ 

123 Returns a list of all the unique elements in the input list. 

124 

125 Args: 

126 seq: input list 

127 

128 Returns: 

129 list of unique elements 

130 

131 As per 

132 https://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-whilst-preserving-order 

133 

134 """ # noqa 

135 seen = set() 

136 seen_add = seen.add 

137 return [x for x in seq if not (x in seen or seen_add(x))] 

138 

139 

140def chunks(x: List[Any], n: int) -> Iterable[List[Any]]: 

141 """ 

142 Yield successive ``n``-sized chunks from the list ``x``. 

143 

144 Args: 

145 x: input list 

146 n: chunk size 

147 

148 Yields: 

149 successive chunks of size ``n`` 

150 

151 """ 

152 for i in range(0, len(x), n): 

153 yield x[i:i + n] 

154 

155 

156def count_bool(blist: Iterable[Any]) -> int: 

157 """ 

158 Counts the number of "truthy" members of the input list. 

159 

160 Args: 

161 blist: list of booleans or other truthy/falsy things 

162 

163 Returns: 

164 number of truthy items 

165 

166 """ 

167 return sum([1 if x else 0 for x in blist])