<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Basics of lists
Step1:  The length of a list is acquired by the len functino
Step2:  Lists can be initialised if its values are known at run time
Step3:  Appending and extending lists
Step4:  Note that the + operator does not modify the lists inplace, rather it 
constructs a new list from the values of l1 and l2. 
If inplace extension is required, the .extend member function should be used
Step5:  Items can be removed from the lists too, with the pop function. 
When called, the pop function removes the last element of the list. 
If an argument is passed into the pop function, the element contained 
at that position in the list is removed, e.g.
Step6:  List comprehension
A powerful feature of the python language is that iteration over 
iterables can be done concisely in one line using list comprehension. 
This technique allows copies, transformation, and filtering of lists, as follows
Step7:  Generaters
In python (especially Python3), generaters are used in many cases. These are objects that perform lazy evaluation (i.e. code is executed when required, not when composed). We will come across these later. 
Filtering and mapping from in-build functions
The operations above can also be achieved with the builtin filter and map functions.
The above operations are demonstrated below
Step8:  Anonymous inline functions (lambdas) can be used if the is_positive function isn't available
Step9:  Mapping functions to lists
The map function takes a function pointer and iterables as parameters. 
The following replicates the list comprehension mapping methods described 
earlier
Step10:  map and filter commands may be nested
Step11:  The map function is very powerful, and makes type conversion very easy
Step12:  Iterating through multiple lists
The zip command takes as arguments a number of lists, and iterates through these 
until the shortest list is traversed. This function therefore aligns lists together. 
Consider the following examples
Step13:  Note, if more than one iterable is passed into map. 
A simplified implementation of map that takes two iterables is given here
python
def map_two(func, iterable1, iterable2)
Step14:  Retreiving the position in the list
The for loops that we have considered iterate over the data elements. 
It is often convenient to also have access to the position in the sequence 
during the iteration. The enumerate function provides this
Step15:  This can also be used in conjunction with the zip function
Step16:  In many applications, it is helpful for the index variable to be offset
by a particular value. This can be achieved with the enumerate function
by passing an optional argument to the function. In this example we start
the indexing with an offset of 100.
<ASSISTANT_TASK:>
Python Code:
from __future__ import print_function
l1 = list() 
l2 = []
print(l1)
print(l2)
Explanation: Basics of lists
End of explanation
print(len(l1))
print(len(l2))
Explanation: The length of a list is acquired by the len functino:
End of explanation
l3 = [1, 2, 3]
print(l3)
print(len(l3))
Explanation: Lists can be initialised if its values are known at run time:
End of explanation
l1.append(1)
print(l1)
l1.append(10)
print(l1)
l2.append(100)
print(l2)
print(l1)
print(l2)
print(l1 + l2)
Explanation: Appending and extending lists
End of explanation
l1.extend(l2)
print(l1)
print(l2)
Explanation: Note that the + operator does not modify the lists inplace, rather it 
constructs a new list from the values of l1 and l2. 
If inplace extension is required, the .extend member function should be used:
End of explanation
l2 = [0, 1, 2, 3, 4, 5, 6]
l2.pop(1)
print(l2)
l2.pop()
print(l2)
print(l1)
Explanation: Items can be removed from the lists too, with the pop function. 
When called, the pop function removes the last element of the list. 
If an argument is passed into the pop function, the element contained 
at that position in the list is removed, e.g.
End of explanation
l3 = [-2, -1, 0, 1, 2]
print(l3)
print(len(l3))
print([el for el in l3])
# Return the positive elements 
print([el for el in l3 if el > 0])
# Return the negative elements 
print([el for el in l3 if el < 0])
# Multiply the elements by two
print([el * 2 for el in l3])
# Multiply filtered elements by two
print([el * 2 for el in l3 if el <= 1])
Explanation: List comprehension
A powerful feature of the python language is that iteration over 
iterables can be done concisely in one line using list comprehension. 
This technique allows copies, transformation, and filtering of lists, as follows:
End of explanation
def is_positive(el): 
    return el > 0
print(l3)
print(filter(is_positive, l3))
print(list(filter(is_positive, l3)))  # python 3
Explanation: Generaters
In python (especially Python3), generaters are used in many cases. These are objects that perform lazy evaluation (i.e. code is executed when required, not when composed). We will come across these later. 
Filtering and mapping from in-build functions
The operations above can also be achieved with the builtin filter and map functions.
The above operations are demonstrated below
End of explanation
# Return the positive elements
print(list(filter(lambda el: el > 0, l3)))
# Return the non-positive elements
print(list(filter(lambda el: el <= 0, l3)))
# Return elements outside of a range
print(list(filter(lambda el: el < -1 or el > 1, l3)))
# Return the elements found within a range (note the mathematical notation)
print(list(filter(lambda el: -1 <= el <= 1, l3)))
Explanation: Anonymous inline functions (lambdas) can be used if the is_positive function isn't available
End of explanation
print([abs(el) for el in l3])
print(list(map(abs, l3)))
def add_one(item): 
    return item + 1
print(list(map(add_one, l3)))
Explanation: Mapping functions to lists
The map function takes a function pointer and iterables as parameters. 
The following replicates the list comprehension mapping methods described 
earlier
End of explanation
print(list(map(lambda el: el * 2, filter(lambda el: el <= 1, l3))))
Explanation: map and filter commands may be nested:
End of explanation
print('Integer array:', list(map(int, l3)))
print('  Float array:', list(map(float, l3)))
print('Boolean array:', list(map(bool, l3)))
Explanation: The map function is very powerful, and makes type conversion very easy:
End of explanation
l4 = [1, 2, 3]
print('l3:', l3)
print('l4:', l4)
for el3, el4 in zip(l3, l4): 
    print(el3, el4)
l5 = l3 + l4
print(l5)
for el3, el4, el5 in zip(l3, l4, l5): 
    print(el3, el4, el5)
Explanation: Iterating through multiple lists
The zip command takes as arguments a number of lists, and iterates through these 
until the shortest list is traversed. This function therefore aligns lists together. 
Consider the following examples:
End of explanation
def add(l, r): 
    try:
        return l * r
    
    except TypeError: 
        # Addition of `None` type is not defined
        return None 
def is_None(l, r): 
    return l is None or r is None
l5 = [5, 4, 3, 2, 1]
print(list(map(add, l4, l5)))
print(list(map(is_None, l4, l5)))
Explanation: Note, if more than one iterable is passed into map. 
A simplified implementation of map that takes two iterables is given here
python
def map_two(func, iterable1, iterable2): 
    out = []
    for iter1, iter2 in zip(iterable1, iterable2): 
        out.append(func(iter1, iter2))
    return out
Note that map copes with 'jagged' iterables in the following way: 
when iterables are not of same length, map will pad the shorter 
lists with None. The returned list is therefore always of the 
same length as the longest iterable.
End of explanation
for index, value in enumerate(l1): 
    print(index, value)
Explanation: Retreiving the position in the list
The for loops that we have considered iterate over the data elements. 
It is often convenient to also have access to the position in the sequence 
during the iteration. The enumerate function provides this:
End of explanation
for index, (el3, el4, el5) in enumerate(zip(l3, l4, l5)): 
    print(index, (el3, el4, el5))
Explanation: This can also be used in conjunction with the zip function:
End of explanation
for index, (el3, el4, el5) in enumerate(zip(l3, l4, l5), start=100): 
    print(index, (el3, el4, el5))
Explanation: In many applications, it is helpful for the index variable to be offset
by a particular value. This can be achieved with the enumerate function
by passing an optional argument to the function. In this example we start
the indexing with an offset of 100.
End of explanation
<END_TASK>