@@ -990,7 +990,7 @@ The following recipes have a more mathematical flavor:
990
990
991
991
def sum_of_squares(it):
992
992
"Add up the squares of the input values."
993
- # sum_of_squares([10, 20, 30]) -> 1400
993
+ # sum_of_squares([10, 20, 30]) -- > 1400
994
994
return math.sumprod(*tee(it))
995
995
996
996
def reshape(matrix, cols):
@@ -1011,17 +1011,16 @@ The following recipes have a more mathematical flavor:
1011
1011
1012
1012
def convolve(signal, kernel):
1013
1013
"""Discrete linear convolution of two iterables.
1014
+ Equivalent to polynomial multiplication.
1014
1015
1015
- The kernel is fully consumed before the calculations begin.
1016
- The signal is consumed lazily and can be infinite.
1017
-
1018
- Convolutions are mathematically commutative.
1019
- If the signal and kernel are swapped,
1020
- the output will be the same.
1016
+ Convolutions are mathematically commutative; however, the inputs are
1017
+ evaluated differently. The signal is consumed lazily and can be
1018
+ infinite. The kernel is fully consumed before the calculations begin.
1021
1019
1022
1020
Article: https://betterexplained.com/articles/intuitive-convolution/
1023
1021
Video: https://www.youtube.com/watch?v=KuXjwB4LzSA
1024
1022
"""
1023
+ # convolve([1, -1, -20], [1, -3]) --> 1 -4 -17 60
1025
1024
# convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
1026
1025
# convolve(data, [1/2, 0, -1/2]) --> 1st derivative estimate
1027
1026
# convolve(data, [1, -2, 1]) --> 2nd derivative estimate
@@ -1059,7 +1058,7 @@ The following recipes have a more mathematical flavor:
1059
1058
f(x) = x³ -4x² -17x + 60
1060
1059
f'(x) = 3x² -8x -17
1061
1060
"""
1062
- # polynomial_derivative([1, -4, -17, 60]) -> [3, -8, -17]
1061
+ # polynomial_derivative([1, -4, -17, 60]) -- > [3, -8, -17]
1063
1062
n = len(coefficients)
1064
1063
powers = reversed(range(1, n))
1065
1064
return list(map(operator.mul, coefficients, powers))
@@ -1161,6 +1160,12 @@ The following recipes have a more mathematical flavor:
1161
1160
1162
1161
>>> take(10 , count())
1163
1162
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1163
+ >>> # Verify that the input is consumed lazily
1164
+ >>> it = iter (' abcdef' )
1165
+ >>> take(3 , it)
1166
+ ['a', 'b', 'c']
1167
+ >>> list (it)
1168
+ ['d', 'e', 'f']
1164
1169
1165
1170
>>> list (prepend(1 , [2 , 3 , 4 ]))
1166
1171
[1, 2, 3, 4]
@@ -1173,25 +1178,45 @@ The following recipes have a more mathematical flavor:
1173
1178
1174
1179
>>> list (tail(3 , ' ABCDEFG' ))
1175
1180
['E', 'F', 'G']
1181
+ >>> # Verify the input is consumed greedily
1182
+ >>> input_iterator = iter (' ABCDEFG' )
1183
+ >>> output_iterator = tail(3 , input_iterator)
1184
+ >>> list (input_iterator)
1185
+ []
1176
1186
1177
1187
>>> it = iter (range (10 ))
1178
1188
>>> consume(it, 3 )
1189
+ >>> # Verify the input is consumed lazily
1179
1190
>>> next (it)
1180
1191
3
1192
+ >>> # Verify the input is consumed completely
1181
1193
>>> consume(it)
1182
1194
>>> next (it, ' Done' )
1183
1195
'Done'
1184
1196
1185
1197
>>> nth(' abcde' , 3 )
1186
1198
'd'
1187
-
1188
1199
>>> nth(' abcde' , 9 ) is None
1189
1200
True
1201
+ >>> # Verify that the input is consumed lazily
1202
+ >>> it = iter (' abcde' )
1203
+ >>> nth(it, 2 )
1204
+ 'c'
1205
+ >>> list (it)
1206
+ ['d', 'e']
1190
1207
1191
1208
>>> [all_equal(s) for s in (' ' , ' A' , ' AAAA' , ' AAAB' , ' AAABA' )]
1192
1209
[True, True, True, False, False]
1193
1210
>>> [all_equal(s, key = str .casefold) for s in (' ' , ' A' , ' AaAa' , ' AAAB' , ' AAABA' )]
1194
1211
[True, True, True, False, False]
1212
+ >>> # Verify that the input is consumed lazily and that only
1213
+ >>> # one element of a second equivalence class is used to disprove
1214
+ >>> # the assertion that all elements are equal.
1215
+ >>> it = iter (' aaabbbccc' )
1216
+ >>> all_equal(it)
1217
+ False
1218
+ >>> ' ' .join(it)
1219
+ 'bbccc'
1195
1220
1196
1221
>>> quantify(range (99 ), lambda x : x% 2 == 0 )
1197
1222
50
@@ -1214,6 +1239,11 @@ The following recipes have a more mathematical flavor:
1214
1239
1215
1240
>>> list (ncycles(' abc' , 3 ))
1216
1241
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
1242
+ >>> # Verify greedy consumption of input iterator
1243
+ >>> input_iterator = iter (' abc' )
1244
+ >>> output_iterator = ncycles(input_iterator, 3 )
1245
+ >>> list (input_iterator)
1246
+ []
1217
1247
1218
1248
>>> sum_of_squares([10 , 20 , 30 ])
1219
1249
1400
@@ -1236,19 +1266,41 @@ The following recipes have a more mathematical flavor:
1236
1266
1237
1267
>>> list (transpose([(1 , 2 , 3 ), (11 , 22 , 33 )]))
1238
1268
[(1, 11), (2, 22), (3, 33)]
1269
+ >>> # Verify that the inputs are consumed lazily
1270
+ >>> input1 = iter ([1 , 2 , 3 ])
1271
+ >>> input2 = iter ([11 , 22 , 33 ])
1272
+ >>> output_iterator = transpose([input1, input2])
1273
+ >>> next (output_iterator)
1274
+ (1, 11)
1275
+ >>> list (zip (input1, input2))
1276
+ [(2, 22), (3, 33)]
1239
1277
1240
1278
>>> list (matmul([(7 , 5 ), (3 , 5 )], [[2 , 5 ], [7 , 9 ]]))
1241
1279
[(49, 80), (41, 60)]
1242
1280
>>> list (matmul([[2 , 5 ], [7 , 9 ], [3 , 4 ]], [[7 , 11 , 5 , 4 , 9 ], [3 , 5 , 2 , 6 , 3 ]]))
1243
1281
[(29, 47, 20, 38, 33), (76, 122, 53, 82, 90), (33, 53, 23, 36, 39)]
1244
1282
1283
+ >>> list (convolve([1 , - 1 , - 20 ], [1 , - 3 ])) == [1 , - 4 , - 17 , 60 ]
1284
+ True
1245
1285
>>> data = [20 , 40 , 24 , 32 , 20 , 28 , 16 ]
1246
1286
>>> list (convolve(data, [0.25 , 0.25 , 0.25 , 0.25 ]))
1247
1287
[5.0, 15.0, 21.0, 29.0, 29.0, 26.0, 24.0, 16.0, 11.0, 4.0]
1248
1288
>>> list (convolve(data, [1 , - 1 ]))
1249
1289
[20, 20, -16, 8, -12, 8, -12, -16]
1250
1290
>>> list (convolve(data, [1 , - 2 , 1 ]))
1251
1291
[20, 0, -36, 24, -20, 20, -20, -4, 16]
1292
+ >>> # Verify signal is consumed lazily and the kernel greedily
1293
+ >>> signal_iterator = iter ([10 , 20 , 30 , 40 , 50 ])
1294
+ >>> kernel_iterator = iter ([1 , 2 , 3 ])
1295
+ >>> output_iterator = convolve(signal_iterator, kernel_iterator)
1296
+ >>> list (kernel_iterator)
1297
+ []
1298
+ >>> next (output_iterator)
1299
+ 10
1300
+ >>> next (output_iterator)
1301
+ 40
1302
+ >>> list (signal_iterator)
1303
+ [30, 40, 50]
1252
1304
1253
1305
>>> from fractions import Fraction
1254
1306
>>> from decimal import Decimal
@@ -1336,6 +1388,17 @@ The following recipes have a more mathematical flavor:
1336
1388
>>> # Test list input. Lists do not support None for the stop argument
1337
1389
>>> list (iter_index(list (' AABCADEAF' ), ' A' ))
1338
1390
[0, 1, 4, 7]
1391
+ >>> # Verify that input is consumed lazily
1392
+ >>> input_iterator = iter (' AABCADEAF' )
1393
+ >>> output_iterator = iter_index(input_iterator, ' A' )
1394
+ >>> next (output_iterator)
1395
+ 0
1396
+ >>> next (output_iterator)
1397
+ 1
1398
+ >>> next (output_iterator)
1399
+ 4
1400
+ >>> ' ' .join(input_iterator)
1401
+ 'DEAF'
1339
1402
1340
1403
>>> list (sieve(30 ))
1341
1404
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
@@ -1487,6 +1550,17 @@ The following recipes have a more mathematical flavor:
1487
1550
[0, 2, 4, 6, 8]
1488
1551
>>> list (odds)
1489
1552
[1, 3, 5, 7, 9]
1553
+ >>> # Verify that the input is consumed lazily
1554
+ >>> input_iterator = iter (range (10 ))
1555
+ >>> evens, odds = partition(is_odd, input_iterator)
1556
+ >>> next (odds)
1557
+ 1
1558
+ >>> next (odds)
1559
+ 3
1560
+ >>> next (evens)
1561
+ 0
1562
+ >>> list (input_iterator)
1563
+ [4, 5, 6, 7, 8, 9]
1490
1564
1491
1565
>>> list (subslices(' ABCD' ))
1492
1566
['A', 'AB', 'ABC', 'ABCD', 'B', 'BC', 'BCD', 'C', 'CD', 'D']
@@ -1506,13 +1580,27 @@ The following recipes have a more mathematical flavor:
1506
1580
['A', 'B', 'C', 'D']
1507
1581
>>> list (unique_everseen(' ABBcCAD' , str .casefold))
1508
1582
['A', 'B', 'c', 'D']
1583
+ >>> # Verify that the input is consumed lazily
1584
+ >>> input_iterator = iter (' AAAABBBCCDAABBB' )
1585
+ >>> output_iterator = unique_everseen(input_iterator)
1586
+ >>> next (output_iterator)
1587
+ 'A'
1588
+ >>> ' ' .join(input_iterator)
1589
+ 'AAABBBCCDAABBB'
1509
1590
1510
1591
>>> list (unique_justseen(' AAAABBBCCDAABBB' ))
1511
1592
['A', 'B', 'C', 'D', 'A', 'B']
1512
1593
>>> list (unique_justseen(' ABBCcAD' , str .casefold))
1513
1594
['A', 'B', 'C', 'A', 'D']
1514
1595
>>> list (unique_justseen(' ABBcCAD' , str .casefold))
1515
1596
['A', 'B', 'c', 'A', 'D']
1597
+ >>> # Verify that the input is consumed lazily
1598
+ >>> input_iterator = iter (' AAAABBBCCDAABBB' )
1599
+ >>> output_iterator = unique_justseen(input_iterator)
1600
+ >>> next (output_iterator)
1601
+ 'A'
1602
+ >>> ' ' .join(input_iterator)
1603
+ 'AAABBBCCDAABBB'
1516
1604
1517
1605
>>> d = dict (a = 1 , b = 2 , c = 3 )
1518
1606
>>> it = iter_except(d.popitem, KeyError )
@@ -1533,6 +1621,12 @@ The following recipes have a more mathematical flavor:
1533
1621
1534
1622
>>> first_true(' ABC0DEF1' , ' 9' , str .isdigit)
1535
1623
'0'
1624
+ >>> # Verify that inputs are consumed lazily
1625
+ >>> it = iter (' ABC0DEF1' )
1626
+ >>> first_true(it, predicate = str .isdigit)
1627
+ '0'
1628
+ >>> ' ' .join(it)
1629
+ 'DEF1'
1536
1630
1537
1631
1538
1632
.. testcode ::
0 commit comments