# Data types, indexing, and slicing

In this article, I would like to briefly review the native data types in Python, comparing with those well-known data types provided by libraries, e.g., NumPy and Pandas, and focus on their essential usages.

List of common data types in Python:

```
```

## int, float, and complex

These are three distinct numeric types in Python: intergers, floating point numbers, and complex numbers.

```
i=2
print(i)             #2
print(type(i))       #class 'int'

f=2.0
print(f)            #2.0
print(type(f))      #class 'float'

c=2+1j
print(c)            #(2+1j)
print(type(c))      #class 'complex'

```

All numeric types (except complex) support the following operations:

Operation Result
`x + y` sum of x and y
`x - y` difference of x and y
`x * y` product of x and y
`x / y` quotient of x and y
`x // y` floored quotient of x and y
`x % y` remainder of `x / y`
`-x` x negated
`+x` x unchanged
`abs(x)` absolute value or magnitude of x
`int(x)` x converted to integer
`float(x)` x converted to floating point
`complex(re, im)` a complex number with real part re, imaginary part imim defaults to zero.
`c.conjugate()` conjugate of the complex number c
`divmod(x, y)` the pair `(x // y, x % y)`
`pow(x, y)` x to the power y
`x ** y` x to the power y

Notes:

x // y also referred to as integer division. The resultant value is a whole integer, though the result’s type is not necessarily int. The result is always rounded towards minus infinity: 1//2 is 0, (-1)//2 is -1, 1//(-2) is -1, and (-1)//(-2) is 0.

`x % y` not for complex numbers. Instead convert to floats using abs() if appropriate.

float(x) also accepts the strings “nan” and “inf” with an optional prefix “+” or “-” for Not a Number (NaN) and positive or negative infinity.

Python defines pow(0, 0) and 0 ** 0 to be 1, as is common for programming languages.

The source of above table is from https://docs.python.org/3/library/stdtypes.html

## string

String operating is absolutely a basic element in all kinds of programming languages. In Python, we put texts into quotes, ” or “”, to form a string. It can also be seen as a sequence of characters, having the same usage of indexing and slicing just like list type.

```
str="Hello World!"
print(str)                    #Hello World!

```

### common string methods

• s.lower(), s.upper() — returns the lowercase or uppercase version of the string
• s.strip() — returns a string with whitespace removed from the start and end
• s.isalpha()/s.isdigit()/s.isspace()… — tests if all the string chars are in the various character classes
• s.startswith(‘other’), s.endswith(‘other’) — tests if the string starts or ends with the given other string
• s.find(‘other’) — searches for the given other string (not a regular expression) within s, and returns the first index where it begins or -1 if not found
• s.replace(‘old’, ‘new’) — returns a string where all occurrences of ‘old’ have been replaced by ‘new’
• s.split(‘delim’) — returns a list of substrings separated by the given delimiter. The delimiter is not a regular expression, it’s just text. ‘aaa,bbb,ccc’.split(‘,’) -> [‘aaa’, ‘bbb’, ‘ccc’]. As a convenient special case s.split() (with no arguments) splits on all whitespace chars.
• s.join(list) — opposite of split(), joins the elements in the given list together using the string as the delimiter. e.g. ‘—‘.join([‘aaa’, ‘bbb’, ‘ccc’]) -> aaa—bbb—ccc

More detail in string methods: https://docs.python.org/3/library/stdtypes.html#string-methods

## list

list is an ordered sequence of items, and items in a list can be of different data types.

Creating a list is very easy: just assign items within a bracket pair [ ]. The syntax for accessing the items of a list is to specify the corresponding indices inside the brackets. Remember, the indexing in Python starts with 0 from left to right, and -1 from right to left. What’s more, with expression by indices and colon symbol, slicing is an easy job in Python. If you omit the first index, the slice starts at the beginning, and vice versa.

```
'''create a list'''
example_list1=list() #an empty list without assigning any item, use list()
example_list1=[1,2,3,4,5]
example_list2=[1,2.0,3,"four",5]
print(example_list1)                      #[1,2,3,4,5]
print(example_list2)                      #[1,2.0,3,'four',5]
""" the above three statements are available """

'''indexing'''
"""different way for indexing, but indicating the same item """
print(example_list2)                 #four
print(example_list2[-2])               #four

"""remember the bool data type? """
print('four' in example_list1)      #False
print('four' in example_list2)      #True

"""list operations (+ operation is easy to understand its functionaloty,
but * operator may result a surprise while processing different data type)"""
print(example_list1+example_list2)               #[1, 2, 3, 4, 5, 1, 2.0, 3, 'four', 5]
print(example_list1 + [example_list2*4]) #[1, 2, 3, 4, 5, 'fourfourfourfour']
print(example_list1 + [example_list2*4]) #[1, 2, 3, 4, 5, 20]

""" list slicing """
print(example_list2[1:4])    #[2.0, 3, 'four']

# here 1:4 means from index 1 and stop by 4, example_list2 is not included in the sliced list
print(example_list2[:-2])    #[1, 2.0, 3]
print(example_list2[:])    #[1, 2.0, 3, 'four', 5]
print(example_list2[1::2])    #[2.0, 'four']
#return every second items from example_list2, commencing from the 1st item

#some supplements
""" remember what I told you about string? you can also convert a string to a list of characters and join them as origin """
print(example_list2)    #o
print(example_list2[1:4])  #our

str='Hello World!'
str2list=list(str)
print(str)       #Hello world!
print(str2list)  #['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!']
list2str="".join(str2list)
print(list2str)  #Hello World!

```

### Common list methods and functions

#### method

• append(x) — append the item x to the end of the list
• pop(x) — returns the x+1 th item from the list and deletes it as well; if no index is provided, it deletes and returns the last item
• extend(x) — takes x as an argument and appends all of the elements
• insert(i,x) — inserts the element x at the given index i, sifting elements to the right
• remove(x) — removes the first item in the list that is equal to x
• del — this operator can also be used to remove items; multiple items are available with a slice index
• reverse() — reverses the order of the items in the list
• sort(x) — sort the items in the list in ascending order (using reverse=True as parameter assignment for descending order)
• index(x) — returns the index of first item that is equal to x

#### function

• max(x)/min(x) — returns the maximum/minimum value from list x
• sum(x) — returns the sum of the values of list x
• len(x) — returns the number of elements in list x
• sorted(x) return a new sorted list but doesn’t sort the list x
```example_list1=[1, 2, 3, 4, 5]
example_list1.append(6)
print(example_list1)      #[1, 2, 3, 4, 5, 6]
example_list1.pop(5)
print(example_list1)      #[1, 2, 3, 4, 5]
example_list1.extend([7,7,8,9])
print(example_list1)      #[1, 2, 3, 4, 5, 7, 7, 8, 9]
example_list1.insert(5,6)
print(example_list1)      #[1, 2, 3, 4, 5, 6, 7, 7, 8, 9]
example_list1.remove(7)
print(example_list1)      #[1, 2, 3, 4, 5, 6, 7, 8, 9]
del example_list1
print(example_list1)      #[1, 2, 3, 5, 6, 7, 8, 9]
del example_list1[1:3]
print(example_list1)      #[1, 5, 6, 7, 8, 9]
del example_list1
'example_list1' in locals()  #False

example_list1=[8,3,7,9,4,2,6,4,8,10]
example_list1.reverse()
print(example_list1)      #[10, 8, 4, 6, 2, 4, 9, 7, 3, 8]
example_list1.sort()
print(example_list1)      #[2, 3, 4, 4, 6, 7, 8, 8, 9, 10]
example_list1.sort(reverse=True)
print(example_list1)      #[10, 9, 8, 8, 7, 6, 4, 4, 3, 2]
print(example_list1.index(3))  #8
print(example_list1.count(8))  #2

print(max(example_list1)) #10
print(min(example_list1)) #2
print(len(example_list1)) #10
print(sorted(example_list1)) #[2, 3, 4, 4, 6, 7, 8, 8, 9, 10]
print(example_list1)        #[10, 9, 8, 8, 7, 6, 4, 4, 3, 2]
```

### nested list

lists can also be included in another list
carefully apply some methods and avoid misunderstanding its usage with a nested list

```L1=;L2=[2,2];L3=[3,3,3]

L=[L1, L2, L3]
print(L)         #[, [2, 2], [3, 3, 3]]
print(L)      #[3, 3, 3]
print(L[1:3]) #[3, 3]

print(len(L))     #3
print(L.count(2)) #0
print(len(L))     #2
print(L.count(2)) #2

```

## tuple

```L1=[1,2,3];L2=[4,5,6];L3=[7,8,9]

#option 1: assign a tuple includes three lists directly
b=(L1,L2,L3)
print(b) #([1, 2, 3], [4, 5, 6], [7, 8, 9])

#option 2: convert a list into tuple
b=()   #create an empty tuple, not necessary for the following statements if b is not in locals()
b=[L1,L2,L3]
b=tuple(b)
print(b)  #([1, 2, 3], [4, 5, 6], [7, 8, 9])

#update the values of elements
#b=[3,3,3] #got error message
b[:]=[3,3,3] #workable
print(b)   #([1, 2, 3], [4, 5, 6], [3, 3, 3])
b[:]=[3,3,3,3] #even change the size of the list for b is workable
print(b)   #([1, 2, 3], [4, 5, 6], [3, 3, 3, 3])
```

## dict

Dictionary
A dictionary is a collection which is unordered, changeable and indexed; a dictionary has a key: value pair. KEYs can be numeric, string, or mixed. We can assign key:value pairs as a dictionary by using curly braces {} or dict() for converting from a nested list. Value for the pair is not limited in a single item, it can be a list or otherwise as well. Performing list(d) on a dictionary returns a list of all the keys used in the dictionary. In order to efficiently create a dictionary, function zip() can be very useful in practice. Since the return data type of zip() is tuple, extra treatment is required if you need a changeable value in generated dictionary. More details of those built-in function zip() and map() can be found as follows:

Related discussion of convert the return of zip() as list can be found as follows:

https://goo.gl/C96sVg

```D={"James":"5'10","John":"6'0","Lisa":"5'2"}
D={"Jamese":"5'10","John":180,"Lisa":"5'2"}
D={"James":["5'10",178],"John":["6'0",183],"Lisa":["5'2",157]}
print(D['John'])   #["6'0", 183]
print(D['John'])  #183
print(list(D))   #['Lisa', 'John', 'James']
D={7:["5'10",178],"John":["6'0",183],"Lisa":["5'2",157]} #key can be interger or string
print(D)  #{'Lisa': ["5'2", 157], 'John': ["6'0", 183], 7: ["5'10", 178]}

#each item in list L can only be a tuple with two elements
L=[("James","5'10"),("John","6'0"),("Lisa","5'2")]
D=dict(L)
print(D)   #{'Lisa': "5'2", 'John': "6'0", 'James': "5'10"}
L=[("James",["5'10",178]),("John",["6'0",183]),("Lisa",["5'2",157])]
D=dict(L)
print(D)   #{'Lisa': ["5'2", 157], 'John': ["6'0", 183], 'James': ["5'10", 178]}

inch=["5'10","6'0","5'2"]
cm=[178,183,157]
name=["James","John","Lisa"]
height=zip(inch,cm)
D=dict(zip(name, height))
print(D)   #{'Lisa': ("5'2", 157), 'John': ("6'0", 183), 'James': ("5'10", 178)}

height=list(map(list, zip(inch,cm)))
D=dict(zip(name, height))
print(D)   #{'Lisa': ["5'2", 157], 'John': ["6'0", 183], 'James': ["5'10", 178]}
```

### Alternative of accessing elements from a dictionary

Please note that if the key doesn’t exist using get() will return None instead of KeyError

```L=[("James",["5'10",178]),("John",["6'0",183]),("Lisa",["5'2",157])]
D=dict(L)

print(D['James'])       #["5'10", 178]
print(D.get('James'))   #["5'10", 178]

#Try these two to catch up the difference between them
#print(D['james'])
#print(D.get('james'))  #None
print(D.get('james','expired')) #expired
```

### Common list methods and functions

#### Method

• update(x) — add key/value pairs to the dictionary; the value would be updated if key has existed
• clear() — remove all items from the dictionary
• copy() — return a shallow copy of the dictionary
• fromkeys(s[,v]) — return a new dictionay with keys from s [optional, and value equal to v]
• get(key [,d]) — return the value of key. If key doesn’t exist, return none (optional, return d)
• items() — return a new view of the key/value
• keys() — return a new view of the dictionary’s key
• pop(key[, d]) — remove the item with key and return corresponding value(s) or KeyError if key doesn’t exist(optional, return d if it has been proveded)
• popitem() — remove and return key/value pair. Raises KeyError if the dictionary is empty.
• setdefault(key [,d]) — insert key with value of d and return d (return None if d isn’t provided); return corresponding value(s) if key is found in the dictionary.
• values() — return a new view of the dictionary’s values
• del — this operator can also be used to remove a particular key/value pair or the whole dictionary

#### function

• len() — return the number of elements in dictionary
• cmp() — compare items of two dictionaries
• sorted() — return a new sorted list of keys in the dictionary
```L=[("James",["5'10",178]),("John",["6'0",183]),("Lisa",["5'2",157])]
D=dict(L)

#update()
D.update({"Mike":["5'1",155],"Jamie":["5'11",180]})
print(D)    #{'James': ["5'10", 178], 'Jamie': ["5'11", 180], 'Mike': ["5'1", 155], 'Lisa': ["5'2", 157], 'John': ["6'0", 183]}
D.update(Mike=["5'2",157],Jamie=["5'11",180])
print(D)    #{'John': ["6'0", 183], 'James': ["5'10", 178], 'Jamie': ["5'11", 180], 'Mike': ["5'2", 157], 'Lisa': ["5'2", 157]}

#fromkeys() and del
k={'a','b','c','d','e'}
v=
D1=dict.fromkeys(k)
D2=dict.fromkeys(k,v)
print(D1)    #{'c': None, 'e': None, 'b': None, 'a': None, 'd': None}
print(D2)    #{'c': , 'e': , 'b': , 'a': , 'd': }
v.append(200)
print(D2)    #{'c': [100, 200], 'e': [100, 200], 'b': [100, 200], 'a': [100, 200], 'd': [100, 200]}

D1=dict.copy(D2)
print(D1) #{'c': [100, 200], 'e': [100, 200], 'b': [100, 200], 'a': [100, 200], 'd': [100, 200]}
D1.clear()
print(D1) #{}

del D2['e']
print(D2)   #{'c': [100, 200], 'b': [100, 200], 'a': [100, 200], 'd': [100, 200]}

#keys(), values and items()
print(D.keys()) #dict_keys(['John', 'James', 'Jamie', 'Mike', 'Lisa'])
print(D.items()) #dict_items([('John', ["6'0", 183]), ('James', ["5'10", 178]), ('Jamie', ["5'11", 180]), ('Mike', ["5'2", 157]), ('Lisa', ["5'2", 157])])
D1=D.items()
print(D1)  #dict_items([('John', ["6'0", 183]), ('James', ["5'10", 178]), ('Jamie', ["5'11", 180]), ('Mike', ["5'2", 157]), ('Lisa', ["5'2", 157])])
del D['John']
print(D1)  #dict_items([('James', ["5'10", 178]), ('Jamie', ["5'11", 180]), ('Mike', ["5'2", 157]), ('Lisa', ["5'2", 157])])

#dict_items and dict_keys can be transferred into dictionary or list
print(dict(D.items()))  #{'James': ["5'10", 178], 'Jamie': ["5'11", 180], 'Mike': ["5'2", 157], 'Lisa': ["5'2", 157]}
print(list(D.items())) #[('James', ["5'10", 178]), ('Jamie', ["5'11", 180]), ('Mike', ["5'2", 157]), ('Lisa', ["5'2", 157])]

#pop and popitem
D1=D.pop('James')
print(D1) #
print(D) #{'Jamie': ["5'11", 180], 'Mike': ["5'2", 157], 'Lisa': ["5'2", 157]}
'''May raise KeyError
D1=D.pop('James')
print(D1)
'''
D1=D.pop('James','no such person')
print(D1)   #no such person

D1=D.popitem()
print(D1)  #('Jamie', ["5'11", 180])
print(D)   #{'Mike': ["5'2", 157], 'Lisa': ["5'2", 157]}
D1=D.popitem()
print(D1)  #('Mike', ["5'2", 157])
print(D)   #{'Lisa': ["5'2", 157]}
D1=D.popitem()
print(D1)   #('Lisa', ["5'2", 157])
print(D)    #{}
D1=D.popitem()
print(D)    # Raise KeyError 'popitem(): dictionary is empty'

print(D2) #{'c': [100, 200], 'b': [100, 200], 'a': [100, 200], 'd': [100, 200]}
print(D2.setdefault('c'))  #[100, 200]
print(D2) #{'c': [100, 200], 'b': [100, 200], 'a': [100, 200], 'd': [100, 200]}

print(D2.setdefault('e',[100,100])) #[100, 100]
print(D2) #{'a': [100, 200], 'd': [100, 200], 'c': [100, 200], 'e': [100, 100], 'b': [100, 200]}
print(D2.setdefault('f') #None
print(D2) #{'f': None, 'a': [100, 200], 'd': [100, 200], 'c': [100, 200], 'e': [100, 100], 'b': [100, 200]}

print(sorted(D2))  #['a', 'b', 'c', 'd', 'e', 'f']
```

## set

a set is a non-ordered collection of items, but each element is unique and immutable.
But set itself is mutable: you can add and remove items.
Integer, float, tuple, and string are allowed for items in a set; mutable objects are not, such as list, dictionary.
Set operations like union, intersection, difference and symmetric difference can be very useful while implementing some algorithms with mathematical set description. ```def init_AB():
global A
global B
A={1,2,3,4,5}
B={3,4,5,6,7}

A={1,2,3,4,5}
print(A)  #{1, 2, 3, 4, 5}
B=[3,4,5,6,7]
B=set(B)
print(B)   #{3, 4, 5, 6, 7}

#Union (using | or mehtod union())
print('A|B=',A|B)   #A|B= {1, 2, 3, 4, 5, 6, 7}
print('A.union(B)=',A.union(B))  #A.union(B)= {1, 2, 3, 4, 5, 6, 7}

#intersection (using & or intersection())
print('A&B=',A&B)   # A&B= {3, 4, 5}
A.intersection_update(B) # let A become the result of A&B
print(A)   #{3, 4, 5}
init_AB()

#difference (using - or difference())
print('A-B=',A-B)    #A-B= {1, 2}
print('B-A=',B-A)   #B-A= {6, 7}
A.difference_update(B) # let A become the result of A-B
print(A) #{1, 2}
#symmetric difference (using ^ or symmetric_diffrence())
print('A^B=',A^B)  #A^B= {1, 2, 3, 4, 5, 6, 7}
A.symmetric_difference_update(B) # let A become the result of A^B
print(A)  #{1, 2, 3, 4, 5, 6, 7}
```

### common set methods and functions

#### methods

• pop(): — remove and return an arbitrary set element. Raise KeyError if the set is empty
• remove(): — remove an element from a set; raise KeyError if the element is not found.
• update(): — update a set with the union of itself and others
• clear(): — remove all elements from the set
• copy(): — return a shallow copy of the set
• discard(x): — remove element x from the set if it is found; otherwise, do nothing
• isdisjoint(): — return True if two sets have a null intersection
• issubset(): — return True if another set contains this set
• issuperset(): — return True if this set contains another set

#### functions

• all() — return True if all elements of the set are true
• any() — return True if any element of the set is true
• len() — return the number of items in the set
• max()/min() — return the largest/smallest item in the set
• sorted() — return a new sorted list
• sum() — return the sum of all elements in the set
```def init_AB():
global A
global B
A={1,2,3,4,5}
B={4,5,6,7,8}

init_AB()
print(A)    #{1, 2, 3, 4, 5, 6}
print(A)
init_AB() #call this function to reset the value of set A and B

print(B.pop(),B.pop())   #8 4
print(B)    #{5, 6, 7}
B.remove(6)
print(B)    #{5, 7}
init_AB()

A.update(B)
print('A=',A," and B=",B) # A= {1, 2, 3, 4, 5, 6, 7, 8}  and B= {8, 4, 5, 6, 7}
B.clear()
print(B)   #set()
B=A.copy()
C=A
A.remove(8);A.remove(7);A.remove(6);A.remove(5)
print('A=',A,'B=', B,'C=',C) # A= {1, 2, 3, 4} B= {1, 2, 3, 4, 5, 6, 7, 8} C= {1, 2, 3, 4}