Strings are the variable type that is used for storing text messages.
s = "Monty Python"
s
'Monty Python'
# length of the string: the number of characters
len(s)
12
# replace a substring in a string with something else
s2 = s.replace("Monty", "Learn")
print(s2)
Learn Python
We just saw that strings can be enclosed in single quotes. In Python, we can equivalently enclose them in double quotes. E.g.,
'my string'
and
"my string"
are the same thing. We can also denote a string with triple quotes. So,
"""my string"""
'''my string'''
"my string"
'my string'
are all the same thing. The difference with triple quotes is that it allows a string to extend over multiple lines.
'''sdj
dfjkd'''
'sdj\ndfjkd'
Now let's try some of these operations on strings. This idea of applying mathematical operations to strings seems strange, but let's just mess around and see what we get.
'Hello, ' + 'world.'
'Hello, world.'
Ah! Adding strings together concatenates them! This is also intuitive. How about subtracting strings?
'Hello, ' - 'world'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In [6], line 1 ----> 1 'Hello, ' - 'world' TypeError: unsupported operand type(s) for -: 'str' and 'str'
That stands to reason. Subtracting strings does not make sense. The Python interpreter was kind enough to give us a nice error message saying that we can't have a str
and a str
operand type for the subtraction operation. It also makes sense that we can't do multiplication, raising of power, etc., with two strings. How about multiplying a string by an integer?
'X'*25
Yes, this makes sense! Multiplication by an integer is the same thing as just adding multiple times, so the Python interpreter concatenates the string several times.
As a final note on operators with strings, watch out for this:
'4' + '2'
'42'
s
'Monty Python'
The result is not 6
, but it is a string containing the characters '4'
and '2'
.
We can index a character in a string 'Monty Python'
stored in variable s
using []
:
s[-1]
'n'
Wait a minute! Shouldn't s[1]
give the first character of the string? It seems to give the second. This is because indexing in Python starts at zero. This is very important. (Historical note: Why Python uses 0-based indexing.)
Indexing in Python starts at zero.
Now, what if we want to pull out multiple characters in a string, called slicing? We can use colons (:
) for that. We can extract a part of a string using the syntax [start:stop]
, which extracts characters between index start
and stop
-1 (the character at index stop
is not included):
s[-3:]
'hon'
We got elements 0
through 4
. When using the colon indexing, s[i:j]
, we get items i
through j-1
. I.e., the range is inclusive of the first index and exclusive of the last. If the slice's final index is larger than the length of the sequence, the slice ends at the last element.
s[6:]
'Python'
Now, we can also use negative indices with colons.
s[-12:-7]
'Monty'
If we omit either (or both) of start
or stop
from [start:stop]
, the default is the beginning and the end of the string, respectively:
s[:7] # First 7 chacter
'Monty P'
s[6:]
'Python'
s[-6:] # Last six characters
'Python'
s[:]
'Monty Python'
We can also specify a stride using the syntax [start:end:stride]
(the default value for stride
is 1). The stride comes after a second colon. For example, if we only wanted the even numbers, we could do the following:
s[1::2]
'ot yhn'
for only the odd numbers, we use:
s[1::2]
'ot yhn'
This technique is called slicing. Read more about the syntax here: https://docs.python.org/3/library/functions.html#slice
So, in general, the indexing scheme is:
s[start:end:stride]
stride
is assumed to be 1.start
is not specified, it is assumed to be zero.end
is not specified, the interpreted assumed you want the entire list.stride
is not specified, it is assumed to be 1.With this in hand, we do lots of crazy slicing. We can even use a negative stride, which results in reversing the string.
s[::-1]
'nohtyP ytnoM'
Python has a very rich set of functions for text processing. See for example https://docs.python.org/3/library/string.html for more information.
print("text1", "text2", "text3") # The print statement concatenates strings with a space
text1 text2 text3
print("text1", 1.0, False, -1j) # The print statements converts all arguments to strings
text1 1.0 False (-0-1j)
print("text1" + "text2" + "text3") # strings added with + are concatenated without space
print(5 + 4)
text1text2text3 9
print("value = %f" % 2.234) # we can use C-style string formatting
value = 2.234000
# this formatting creates a string
s2 = "Value_1 = %.2f | Value_2 = %d" % (3.1415, 1.5)
print(s2)
Value_1 = 3.14 | Value_2 = 1
# alternative, more intuitive way of formatting a string
s3 = 'Value_1 = {1} | Value_2 = {0}'.format(3.1415, 1.5)
print(s3)
Value_1 = 1.5 | Value_2 = 3.1415
Python3.6 introduced a new string formatting mechanism known as Literal String Interpolation or more commonly as F-strings (because of the leading f character preceding the string literal).
name = "Eric"
points = 74
print(f'Hello, {name}. You have {points} points from the last test.')
Hello, Eric. You have 74 points from the last test.
Lists are very similar to strings, except that each element can be of any type. Lists play a very important role in Python. For example they are used in loops and other flow control structures (discussed below).
The syntax for creating lists in Python is [...]
:
l = [1,2,3,4]
print(type(l))
print(l)
<class 'list'> [1, 2, 3, 4]
We can use the same slicing techniques to manipulate lists as we could use on strings:
print(l)
print(l[1:3])
print(l[::2])
[1, 2, 3, 4] [2, 3] [1, 3]
l[::-1]
[4, 3, 2, 1]
Heads up MATLAB users: Indexing starts at 0!
l[0:2]
[1, 2]
Elements in a list do not all have to be of the same type:
l = [1, 'dfa', 1.0, 1-1j]
print(l)
[1, 'dfa', 1.0, (1-1j)]
l[1][0]
'd'
Python lists can be inhomogeneous and arbitrarily nested:
l = [[1, 3],
[6, 4]]
nested_list = [1, [2, [3, [4, [5]]]]]
nested_list
[1, [2, [3, [4, [5]]]]]
Convert a string to a list by type casting
a = '154.56'
b = '982.434'
float(a) + float(b)
1136.994
s2 = list('Python')
s2
['P', 'y', 't', 'h', 'o', 'n']
# sorting lists
s2.sort()
print(s2)
['P', 'h', 'n', 'o', 't', 'y']
[1,2,3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]
We can add one item to a list using the append
method or add several items using extend
method.
# create a new empty list
l = []
# add an elements using `append`
l.append("A")
l.append("d")
l.append("a")
print(l)
['A', 'd', 'a']
l
['A', 'd', 'a']
l.extend([' ', 'M', 'o', 'r', 'e'])
print(l)
['A', 'd', 'a', ' ', 'M', 'o', 'r', 'e']
l1 = [1, 2, 3]
l2 = [5, 6, 7]
l3 = l1 + l2
print(l1, l2, l3)
[1, 2, 3] [5, 6, 7] [1, 2, 3, 5, 6, 7]
We can modify lists by assigning new values to elements in the list. In technical jargon, lists are mutable.
l[1] = "p"
l[2] = "p"
print(l)
['A', 'p', 'p', ' ', 'M', 'o', 'r', 'e']
l[1:3] = ["d", "d"]
print(l)
['A', 'd', 'd', ' ', 'M', 'o', 'r', 'e']
Insert an element at an specific index using insert
l.insert(0, " ")
l.insert(0, "k")
l.insert(0, "c")
l.insert(0, "a")
l.insert(0, "B")
print(l)
['B', 'a', 'c', 'k', ' ', 'A', 'd', 'd', ' ', 'M', 'o', 'r', 'e']
Remove first element with specific value using 'remove'
l.remove(" ")
print(l)
['B', 'a', 'c', 'k', 'A', 'd', 'd', ' ', 'M', 'o', 'r', 'e']
Remove an element at a specific location using del
:
del l[6]
del l[5]
del l[4]
print(l)
['B', 'a', 'c', 'k', ' ', 'M', 'o', 'r', 'e']
s = list('Hello')
del s[2]
del s[2]
print(s)
['H', 'e', 'o']
'M' in l
True
l2 = [' ', 'A', 'd', 'd']
l + l2
['B', 'a', 'c', 'k', ' ', 'M', 'o', 'r', 'e', ' ', 'A', 'd', 'd']
l, point
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In [51], line 1 ----> 1 l, point NameError: name 'point' is not defined
l[0] = 'A'
l
['A', 'a', 'c', 'k', ' ', 'M', 'o', 'r', 'e']
point[0]
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In [53], line 1 ----> 1 point[0] NameError: name 'point' is not defined
Methods that are available with list objects in Python programming are tabulated below.
They are accessed as list.method(). Some of the methods have already been used above.
Python List Methods
append()
- Add an element to the end of the listextend()
- Add all elements of a list to the another listinsert()
- Insert an item at the defined indexremove()
- Removes an item from the listpop()
- Removes and returns an element at the given indexclear()
- Removes all items from the listindex()
- Returns the index of the first matched itemcount()
- Returns the count of the number of items passed as an argumentsort()
- Sort items in a list in ascending orderreverse()
- Reverse the order of items in the listcopy()
- Returns a shallow copy of the listSee help(list)
for more details, or read the online documentation
a, b = 5, 6
x
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In [55], line 1 ----> 1 x NameError: name 'x' is not defined
Tuples are like lists, except that they cannot be modified once created, that is they are immutable.
In Python, tuples are created using the syntax (..., ..., ...)
, or even ..., ...
:
point = (10, 20)
print(point, type(point))
(10, 20) <class 'tuple'>
point = 10, 20
print(point, type(point))
(10, 20) <class 'tuple'>
We can unpack a tuple by assigning it to a comma-separated list of variables:
x, y = point
y
20
If we try to assign a new value to an element in a tuple we get an error:
point[0] = 20
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In [59], line 1 ----> 1 point[0] = 20 TypeError: 'tuple' object does not support item assignment
Dictionaries are also like lists, except that each element is a key-value pair. The syntax for dictionaries is {key1 : value1, ...}
:
d = {'a':10, 'b':25, 7:'Ondrej'}
d
{'a': 10, 'b': 25, 7: 'Ondrej'}
d['c'] = 30
d
{'a': 10, 'b': 25, 7: 'Ondrej', 'c': 30}
rock = {"density" : 2830.3,
"texture" : "porphyritic",
"minerals" : ["quartz", "feldspar", "white mica"]}
print(type(rock))
print(rock)
<class 'dict'> {'density': 2830.3, 'texture': 'porphyritic', 'minerals': ['quartz', 'feldspar', 'white mica']}
print("density = {}".format(rock["density"]))
print("texture = {}".format(rock["texture"]))
print("minerals = {}".format(rock["minerals"]))
density = 2830.3 texture = porphyritic minerals = ['quartz', 'feldspar', 'white mica']
rock["density"] = 2760.4
rock["texture"] = "phaneritic"
# add a new entry
rock["porosity"] = 0.072
print("density = {}".format(rock["density"]))
print("texture = {}".format(rock["texture"]))
print("minerals = {}".format(rock["minerals"]))
print("porosity = {}".format(rock["porosity"]))
rock
density = 2760.4 texture = phaneritic minerals = ['quartz', 'feldspar', 'white mica'] porosity = 0.072
{'density': 2760.4, 'texture': 'phaneritic', 'minerals': ['quartz', 'feldspar', 'white mica'], 'porosity': 0.072}
A set is unordered collection of unique elements. Common uses include membership testing, removing duplicates from a sequence, and computing standard math operations on sets such as intersection, union, difference, and symmetric difference.
It can have any number of items and they may be of different types (integer, float, tuple, string etc.). But a set cannot have mutable elements like lists, sets or dictionaries as its elements.
# Different types of sets in Python
# set of integers
m = {1, 2, 3}
print(type(m), m)
<class 'set'> {1, 2, 3}
# set of mixed datatypes
n = {1.0, "Hello", (1, 2, 3)}
print(n)
{1.0, (1, 2, 3), 'Hello'}
Sets cannot have duplicates
m = {1, 2, 3, 4, 3, 2}
print(m)
{1, 2, 3, 4}
s = 'Hi there. How many different characters i just type'
len(set(s))
21
We can make set from a list and list from set
l = [1, 2, 1, 1, 2, 3, 1, 3]
m = set(l)
print(m)
k = list(m)
print(k)
{1, 2, 3} [1, 2, 3]
We can add a single element using the add
method, and multiple elements using the update
method. The update
method can take tuples, lists, strings or other sets as its argument. In all cases, duplicates are avoided.
m = {1, 3}
print(m)
# add an element
m.add(2)
print(m)
m.update([2, 3, 4])
print(m)
m.update([4, 5], {1, 6, 8})
print(m)
{1, 3} {1, 2, 3} {1, 2, 3, 4} {1, 2, 3, 4, 5, 6, 8}
A particular item can be removed from a set using the methods discard
and remove
.
The only difference between the two is that the discard
function leaves a set unchanged if the element is not present in the set. On the other hand, the remove
function will raise an error in such a condition (if element is not present in the set).
# initialize my_set
m = {1, 3, 4, 5, 6}
print(m)
# discard an element
m.discard(4)
print(m)
# remove an element
m.remove(6)
print(m)
m.discard(2)
print(m)
m.remove(2)
{1, 3, 4, 5, 6} {1, 3, 5, 6} {1, 3, 5} {1, 3, 5}
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) Cell In [73], line 16 13 m.discard(2) 14 print(m) ---> 16 m.remove(2) KeyError: 2
Sets can be used to carry out mathematical set operations like union, intersection, difference and symmetric difference. We can do this with operators or methods.
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
Union of A and B is a set of all elements from both sets.
print(A | B)
print(A.union(B))
{1, 2, 3, 4, 5, 6, 7, 8} {1, 2, 3, 4, 5, 6, 7, 8}
Intersection of A and B is a set of elements that are common in both the sets.
print(B & A)
print(A.intersection(B))
{4, 5} {4, 5}
Difference of the set B from set A (A - B) is a set of elements that are only in A but not in B. Similarly, B - A is a set of elements in B but not in A.## Control Flow
print(A - B)
print(A.difference(B))
{1, 2, 3} {1, 2, 3}
print(B - A)
print(B.difference(A))
{8, 6, 7} {8, 6, 7}
Symmetric Difference of A and B is a set of elements in A and B but not in both (excluding the intersection).
print(A ^ B)
print(A.symmetric_difference(B))
{1, 2, 3, 6, 7, 8} {1, 2, 3, 6, 7, 8}
See help(set)
for more details, or read the online documentation
The Python syntax for conditional execution of code uses the keywords if
, elif
(else if), else
if
statement contains particular condition, if the condition will be true, the code block which is written under if statement will execute.
if True:
print(1)
print(2)
print(3)
print(5)
1 2 3 5
condition1 = False
condition2 = False
if condition1:
print("condition1 is True")
if condition2:
print("condition2 is True")
print("All decisions done.")
if
statement contains particular condition, if the condition will be true, the code block which is written under if
statement will execute, otherwise code block which is written under else
statement will execute.
condition1 = True
condition2 = False
if condition1:
print("condition1 is True")
print('dgfg')
print('dfef')
else:
print("condition1 is False")
if condition2:
print("condition2 is True")
else:
print("condition2 is False")
print("All decisions done.")
condition1 is True dgfg dfef condition2 is False All decisions done.
When a series of decision are involved, we may have to use more then one if-else statement in the nested form.
condition1 = False
condition2 = False
if condition1:
if condition2:
print("condition1 and condition2 are True")
else:
print("condition1 is True and condition2 is False")
else:
print("condition1 is False")
In Python, elif
statement is the same as an else-if statement of other programming languages. Sometimes we need to check some conditions when if
condition is false.
score = 65
if score < 50:
print('Fail')
elif score < 65:
print('C')
elif score < 80:
print('B')
else:
print('A')
B
5 > 7
condition1 = True
condition2 = True
if condition1 and condition2:
print("Both conditions are True")
else:
print("At least one condition is False")
For the first time, here we encounted a peculiar and unusual aspect of the Python programming language: Program blocks are defined by their indentation level.
Compare to the equivalent C code:
if (statement1)
{
printf("statement1 is True\n");
}
else if (statement2)
{
printf("statement2 is True\n");
}
else
{
printf("statement1 and statement2 are False\n");
}
In C blocks are defined by the enclosing curly brakets {
and }
. And the level of indentation (white space before the code statements) does not matter (completely optional).
But in Python, the extent of a code block is defined by the indentation level (usually a tab or say four white spaces). This means that we have to be careful to indent our code correctly, or else we will get syntax errors.
condition1 = condition2 = True
if condition1:
if condition2:
print("Both condition1 and condition2 are True")
Both condition1 and condition2 are True
# Bad indentation!
if condition1:
if condition2:
print("Both condition1 and condition2 are True") # this line is not properly indented
Cell In [87], line 4 print("Both condition1 and condition2 are True") # this line is not properly indented ^ IndentationError: expected an indented block after 'if' statement on line 3
condition1 = True
if condition1:
print("printed if condition1 is True")
#kj ksj
print("still inside the if block")
condition1 = False
if condition1:
print("printed if condition1 is True")
print("now outside the if block")
In Python, loops can be programmed in a number of different ways. The most common is the for
loop, which is used together with iterable objects, such as lists. The basic syntax is:
for
loops:¶for x in ['a', 5, 1, 1000, 'rere']:
print(x)
a 5 1 1000 rere
list(range(5, 20, 2))
[5, 7, 9, 11, 13, 15, 17, 19]
for a in range(5, 20, 2):
print(a)
5 7 9 11 13 15 17 19
list(range(5))
[0, 1, 2, 3, 4]
The for
loop iterates over the elements of the supplied list, and executes the containing block once for each element. Any kind of iterable object could be used in the for
loop. For example, the range
function generates an interator, which could be used:
for x in range(5): # by default range start at 0
print('This is loop {}'.format(x + 1))
This is loop 1 This is loop 2 This is loop 3 This is loop 4 This is loop 5
Note: range(4)
does not include 4 !
for x in range(-3, 3):
print(x)
start = 10
stop = 30
step = 2
for x in range(start, stop, step):
print(x)
10 12 14 16 18 20 22 24 26 28
Note: stop
value is not included !
for word in ["scientific", "computing", "with", "python"]:
print(word)
scientific computing with python
In mathematics, the Fibonacci numbers, commonly denoted $F_n$ form a sequence, called the Fibonacci sequence, such that each number is the sum of the two preceding ones, starting from 0 and 1. That is $F_{0}=0$, $F_{1}=1$ and $F_{n}=F_{n-1}+F_{n-2}$ for $n>1$. Let's makesmall script to generate list of 20 Fibonacci numbers:
N = 30 # Desired amount of Fibonacci numbers
F = [0, 1]
for x in range(N - 2): # we have two numbers already
F.append(F[-2] + F[-1])
print(F)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229]
It is known, that the ratio of each successive pair of numbers in the Fibonacci sequence converge on the golden ratio $\varphi ={\frac {1+{\sqrt {5}}}{2}}=1.6180339887\ldots$ as you go higher in the sequence. So let's test it.
F = [0, 1]
ratio = []
for x in range(500):
F.append(F[-2] + F[-1])
ratio.append(F[-1] / F[-2])
print(ratio[-1])
print("Last value approaching {}".format((1 + 5**0.5)/2))
1.618033988749895 Last value approaching 1.618033988749895
In loop definition, we can use unpacking to assign values to more variables
points = [(1,3), (5,3), (2,7)]
for x, y in points:
print((x**2 + y**2)**0.5)
3.1622776601683795 5.830951894845301 7.280109889280518
points = [(1,3), (5,3), (2,7)]
for x in points:
print((x[0]**2 + x[1]**2)**0.5)
3.1622776601683795 5.830951894845301 7.280109889280518
Sometimes it is useful to have access to the indices of the values when iterating over a list. We can use the enumerate
function for this:
planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
for idx, p in enumerate(planets):
print(idx, p)
0 Mercury 1 Venus 2 Earth 3 Mars 4 Jupiter 5 Saturn 6 Uranus 7 Neptune
planets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune']
for idx in range(len(planets)):
print(idx, planets[idx])
0 Mercury 1 Venus 2 Earth 3 Mars 4 Jupiter 5 Saturn 6 Uranus 7 Neptune
Sometimes it is useful to iterate over several lists simultaneously. We can use the zip
function for this:
names = ['John', 'Eva', 'George']
ages = [24, 19, 31]
for age, name in zip(ages, names):
print(age, name)
24 John 19 Eva 31 George
break
statement could be used to abandon loop earlier
l = [2, 3, 6, 3, 1, 4, 6, 7, 4, 11, 3, 3, 5, 6, 11, 2]
for pos, val in enumerate(l):
if val == 11:
print('I found 11 at position {}.'.format(pos))
break
n = 10
while n > 4:
n = n - 1
print(n)
print('Done.')
9 8 7 6 5 4 Done.
v = 4362538557
estimate = 1
err = 1
n = 0
while err > 1e-12:
estimate = (estimate + v/estimate)/2
n += 1
err = abs(v - estimate*estimate)
print(n, estimate, estimate*estimate)
21 66049.51594826415 4362538557.0
x = (x + v/x)/2
x
x*x
Let's create small program to find all factors of number
N = 712
factors = []
while N > 1:
for d in range(2, N + 1):
if N % d == 0:
factors.append(d)
N = N // d
break
print(factors)
for
loops:¶A convenient and compact way to initialize lists:
squares = []
for x in range(100):
squares.append(x * x)
print(squares)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]
squares = [x * x for x in range(100)]
print(squares)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801]
You can use conditional logic in comprehensions
l1 = []
for x in range(100):
if x % 2 == 0:
l1.append(x**2)
print(l1)
[0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784, 900, 1024, 1156, 1296, 1444, 1600, 1764, 1936, 2116, 2304, 2500, 2704, 2916, 3136, 3364, 3600, 3844, 4096, 4356, 4624, 4900, 5184, 5476, 5776, 6084, 6400, 6724, 7056, 7396, 7744, 8100, 8464, 8836, 9216, 9604]
l1 = [x**2 for x in range(100) if x % 2 == 0]
print(l1)
[0, 4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576, 676, 784, 900, 1024, 1156, 1296, 1444, 1600, 1764, 1936, 2116, 2304, 2500, 2704, 2916, 3136, 3364, 3600, 3844, 4096, 4356, 4624, 4900, 5184, 5476, 5776, 6084, 6400, 6724, 7056, 7396, 7744, 8100, 8464, 8836, 9216, 9604]