@@ -998,7 +998,7 @@ The following recipes have a more mathematical flavor:
998
998
999
999
def sum_of_squares(it):
1000
1000
"Add up the squares of the input values."
1001
- # sum_of_squares([10, 20, 30]) -> 1400
1001
+ # sum_of_squares([10, 20, 30]) -- > 1400
1002
1002
return math.sumprod(*tee(it))
1003
1003
1004
1004
def reshape(matrix, cols):
@@ -1019,17 +1019,16 @@ The following recipes have a more mathematical flavor:
1019
1019
1020
1020
def convolve(signal, kernel):
1021
1021
"""Discrete linear convolution of two iterables.
1022
+ Equivalent to polynomial multiplication.
1022
1023
1023
- The kernel is fully consumed before the calculations begin.
1024
- The signal is consumed lazily and can be infinite.
1025
-
1026
- Convolutions are mathematically commutative.
1027
- If the signal and kernel are swapped,
1028
- the output will be the same.
1024
+ Convolutions are mathematically commutative; however, the inputs are
1025
+ evaluated differently. The signal is consumed lazily and can be
1026
+ infinite. The kernel is fully consumed before the calculations begin.
1029
1027
1030
1028
Article: https://betterexplained.com/articles/intuitive-convolution/
1031
1029
Video: https://www.youtube.com/watch?v=KuXjwB4LzSA
1032
1030
"""
1031
+ # convolve([1, -1, -20], [1, -3]) --> 1 -4 -17 60
1033
1032
# convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
1034
1033
# convolve(data, [1/2, 0, -1/2]) --> 1st derivative estimate
1035
1034
# convolve(data, [1, -2, 1]) --> 2nd derivative estimate
@@ -1067,7 +1066,7 @@ The following recipes have a more mathematical flavor:
1067
1066
f(x) = x³ -4x² -17x + 60
1068
1067
f'(x) = 3x² -8x -17
1069
1068
"""
1070
- # polynomial_derivative([1, -4, -17, 60]) -> [3, -8, -17]
1069
+ # polynomial_derivative([1, -4, -17, 60]) -- > [3, -8, -17]
1071
1070
n = len(coefficients)
1072
1071
powers = reversed(range(1, n))
1073
1072
return list(map(operator.mul, coefficients, powers))
@@ -1169,6 +1168,12 @@ The following recipes have a more mathematical flavor:
1169
1168
1170
1169
>>> take(10 , count())
1171
1170
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1171
+ >>> # Verify that the input is consumed lazily
1172
+ >>> it = iter (' abcdef' )
1173
+ >>> take(3 , it)
1174
+ ['a', 'b', 'c']
1175
+ >>> list (it)
1176
+ ['d', 'e', 'f']
1172
1177
1173
1178
>>> list (prepend(1 , [2 , 3 , 4 ]))
1174
1179
[1, 2, 3, 4]
@@ -1181,25 +1186,45 @@ The following recipes have a more mathematical flavor:
1181
1186
1182
1187
>>> list (tail(3 , ' ABCDEFG' ))
1183
1188
['E', 'F', 'G']
1189
+ >>> # Verify the input is consumed greedily
1190
+ >>> input_iterator = iter (' ABCDEFG' )
1191
+ >>> output_iterator = tail(3 , input_iterator)
1192
+ >>> list (input_iterator)
1193
+ []
1184
1194
1185
1195
>>> it = iter (range (10 ))
1186
1196
>>> consume(it, 3 )
1197
+ >>> # Verify the input is consumed lazily
1187
1198
>>> next (it)
1188
1199
3
1200
+ >>> # Verify the input is consumed completely
1189
1201
>>> consume(it)
1190
1202
>>> next (it, ' Done' )
1191
1203
'Done'
1192
1204
1193
1205
>>> nth(' abcde' , 3 )
1194
1206
'd'
1195
-
1196
1207
>>> nth(' abcde' , 9 ) is None
1197
1208
True
1209
+ >>> # Verify that the input is consumed lazily
1210
+ >>> it = iter (' abcde' )
1211
+ >>> nth(it, 2 )
1212
+ 'c'
1213
+ >>> list (it)
1214
+ ['d', 'e']
1198
1215
1199
1216
>>> [all_equal(s) for s in (' ' , ' A' , ' AAAA' , ' AAAB' , ' AAABA' )]
1200
1217
[True, True, True, False, False]
1201
1218
>>> [all_equal(s, key = str .casefold) for s in (' ' , ' A' , ' AaAa' , ' AAAB' , ' AAABA' )]
1202
1219
[True, True, True, False, False]
1220
+ >>> # Verify that the input is consumed lazily and that only
1221
+ >>> # one element of a second equivalence class is used to disprove
1222
+ >>> # the assertion that all elements are equal.
1223
+ >>> it = iter (' aaabbbccc' )
1224
+ >>> all_equal(it)
1225
+ False
1226
+ >>> ' ' .join(it)
1227
+ 'bbccc'
1203
1228
1204
1229
>>> quantify(range (99 ), lambda x : x% 2 == 0 )
1205
1230
50
@@ -1222,6 +1247,11 @@ The following recipes have a more mathematical flavor:
1222
1247
1223
1248
>>> list (ncycles(' abc' , 3 ))
1224
1249
['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']
1250
+ >>> # Verify greedy consumption of input iterator
1251
+ >>> input_iterator = iter (' abc' )
1252
+ >>> output_iterator = ncycles(input_iterator, 3 )
1253
+ >>> list (input_iterator)
1254
+ []
1225
1255
1226
1256
>>> sum_of_squares([10 , 20 , 30 ])
1227
1257
1400
@@ -1248,19 +1278,41 @@ The following recipes have a more mathematical flavor:
1248
1278
1249
1279
>>> list (transpose([(1 , 2 , 3 ), (11 , 22 , 33 )]))
1250
1280
[(1, 11), (2, 22), (3, 33)]
1281
+ >>> # Verify that the inputs are consumed lazily
1282
+ >>> input1 = iter ([1 , 2 , 3 ])
1283
+ >>> input2 = iter ([11 , 22 , 33 ])
1284
+ >>> output_iterator = transpose([input1, input2])
1285
+ >>> next (output_iterator)
1286
+ (1, 11)
1287
+ >>> list (zip (input1, input2))
1288
+ [(2, 22), (3, 33)]
1251
1289
1252
1290
>>> list (matmul([(7 , 5 ), (3 , 5 )], [[2 , 5 ], [7 , 9 ]]))
1253
1291
[(49, 80), (41, 60)]
1254
1292
>>> list (matmul([[2 , 5 ], [7 , 9 ], [3 , 4 ]], [[7 , 11 , 5 , 4 , 9 ], [3 , 5 , 2 , 6 , 3 ]]))
1255
1293
[(29, 47, 20, 38, 33), (76, 122, 53, 82, 90), (33, 53, 23, 36, 39)]
1256
1294
1295
+ >>> list (convolve([1 , - 1 , - 20 ], [1 , - 3 ])) == [1 , - 4 , - 17 , 60 ]
1296
+ True
1257
1297
>>> data = [20 , 40 , 24 , 32 , 20 , 28 , 16 ]
1258
1298
>>> list (convolve(data, [0.25 , 0.25 , 0.25 , 0.25 ]))
1259
1299
[5.0, 15.0, 21.0, 29.0, 29.0, 26.0, 24.0, 16.0, 11.0, 4.0]
1260
1300
>>> list (convolve(data, [1 , - 1 ]))
1261
1301
[20, 20, -16, 8, -12, 8, -12, -16]
1262
1302
>>> list (convolve(data, [1 , - 2 , 1 ]))
1263
1303
[20, 0, -36, 24, -20, 20, -20, -4, 16]
1304
+ >>> # Verify signal is consumed lazily and the kernel greedily
1305
+ >>> signal_iterator = iter ([10 , 20 , 30 , 40 , 50 ])
1306
+ >>> kernel_iterator = iter ([1 , 2 , 3 ])
1307
+ >>> output_iterator = convolve(signal_iterator, kernel_iterator)
1308
+ >>> list (kernel_iterator)
1309
+ []
1310
+ >>> next (output_iterator)
1311
+ 10
1312
+ >>> next (output_iterator)
1313
+ 40
1314
+ >>> list (signal_iterator)
1315
+ [30, 40, 50]
1264
1316
1265
1317
>>> from fractions import Fraction
1266
1318
>>> from decimal import Decimal
@@ -1348,6 +1400,17 @@ The following recipes have a more mathematical flavor:
1348
1400
>>> # Test list input. Lists do not support None for the stop argument
1349
1401
>>> list (iter_index(list (' AABCADEAF' ), ' A' ))
1350
1402
[0, 1, 4, 7]
1403
+ >>> # Verify that input is consumed lazily
1404
+ >>> input_iterator = iter (' AABCADEAF' )
1405
+ >>> output_iterator = iter_index(input_iterator, ' A' )
1406
+ >>> next (output_iterator)
1407
+ 0
1408
+ >>> next (output_iterator)
1409
+ 1
1410
+ >>> next (output_iterator)
1411
+ 4
1412
+ >>> ' ' .join(input_iterator)
1413
+ 'DEAF'
1351
1414
1352
1415
>>> list (sieve(30 ))
1353
1416
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
@@ -1499,6 +1562,17 @@ The following recipes have a more mathematical flavor:
1499
1562
[0, 2, 4, 6, 8]
1500
1563
>>> list (odds)
1501
1564
[1, 3, 5, 7, 9]
1565
+ >>> # Verify that the input is consumed lazily
1566
+ >>> input_iterator = iter (range (10 ))
1567
+ >>> evens, odds = partition(is_odd, input_iterator)
1568
+ >>> next (odds)
1569
+ 1
1570
+ >>> next (odds)
1571
+ 3
1572
+ >>> next (evens)
1573
+ 0
1574
+ >>> list (input_iterator)
1575
+ [4, 5, 6, 7, 8, 9]
1502
1576
1503
1577
>>> list (subslices(' ABCD' ))
1504
1578
['A', 'AB', 'ABC', 'ABCD', 'B', 'BC', 'BCD', 'C', 'CD', 'D']
@@ -1518,13 +1592,27 @@ The following recipes have a more mathematical flavor:
1518
1592
['A', 'B', 'C', 'D']
1519
1593
>>> list (unique_everseen(' ABBcCAD' , str .casefold))
1520
1594
['A', 'B', 'c', 'D']
1595
+ >>> # Verify that the input is consumed lazily
1596
+ >>> input_iterator = iter (' AAAABBBCCDAABBB' )
1597
+ >>> output_iterator = unique_everseen(input_iterator)
1598
+ >>> next (output_iterator)
1599
+ 'A'
1600
+ >>> ' ' .join(input_iterator)
1601
+ 'AAABBBCCDAABBB'
1521
1602
1522
1603
>>> list (unique_justseen(' AAAABBBCCDAABBB' ))
1523
1604
['A', 'B', 'C', 'D', 'A', 'B']
1524
1605
>>> list (unique_justseen(' ABBCcAD' , str .casefold))
1525
1606
['A', 'B', 'C', 'A', 'D']
1526
1607
>>> list (unique_justseen(' ABBcCAD' , str .casefold))
1527
1608
['A', 'B', 'c', 'A', 'D']
1609
+ >>> # Verify that the input is consumed lazily
1610
+ >>> input_iterator = iter (' AAAABBBCCDAABBB' )
1611
+ >>> output_iterator = unique_justseen(input_iterator)
1612
+ >>> next (output_iterator)
1613
+ 'A'
1614
+ >>> ' ' .join(input_iterator)
1615
+ 'AAABBBCCDAABBB'
1528
1616
1529
1617
>>> d = dict (a = 1 , b = 2 , c = 3 )
1530
1618
>>> it = iter_except(d.popitem, KeyError )
@@ -1545,6 +1633,12 @@ The following recipes have a more mathematical flavor:
1545
1633
1546
1634
>>> first_true(' ABC0DEF1' , ' 9' , str .isdigit)
1547
1635
'0'
1636
+ >>> # Verify that inputs are consumed lazily
1637
+ >>> it = iter (' ABC0DEF1' )
1638
+ >>> first_true(it, predicate = str .isdigit)
1639
+ '0'
1640
+ >>> ' ' .join(it)
1641
+ 'DEF1'
1548
1642
1549
1643
1550
1644
.. testcode ::
0 commit comments