How simple list functions could be implemented in Python - python

I know that Python has built-in list functions but I'm curious as to how one would write a function to sum a list and a function to reverse a list. I was able to figure out how to write some other list functions (sort, count, index, etc.) but not these, and I imagine some other languages don't have these built-in functions.
Could someone show me some Python code for those 2 functions, not using any other built-in functions?

For summing a list, you can do:
sum([1, 2, 3, 4])
And for reversing a list, this will return a new, reversed list by using Python's slices:
[1, 2, 3, 4][::-1]
Now if you don't want to use built-in functions:
def sum(lst):
s = 0
for e in lst:
s += e
return s
def reverse(lst):
l = []
for e in lst:
l = [e] + l
return l

Sum a list
Straight from the Python manual:
>>> def sum(seq):
... def add(x,y): return x+y
... return reduce(add, seq, 0)
>>> sum(range(1, 11))
55
>>> sum([])
0
This could be done as a one-liner (...ish) using lambda (Python's anonymous function syntax):
def sum(seq):
return reduce(lambda x, y: x + y, seq, 0)
Don't want to use reduce?
def sum(seq):
total = 0
for s in seq:
total += s
return total

Related

Takes array as parameter and returns a reverse array using loop

# Function that takes array as parameter and returns a reverse array
# using loop
def reverse_list(arr = []):
for i in arr[::-1]:
print(i)
arr_num = [1, 2, 3, 4, 5]
print(reverse_list(arr_num))
I want my function to take an array as a parameter, but I'm not sure if the structure /code of it is correct. 
Your function will not work since it's not returning the list.
Here is one way to solve this problem - using the for-loop:
def reverse_list(arr):
result = []
for i, _ in enumerate(arr): # try to use enumerate - it's better in most cases
result.append(arr[~i]) # use the backward indexing here
return result
Simply create a new array inside the function and either append each values before returning it
def reverse_list(arr = []):
new_arr = []
for i in arr[::-1]:
# print(i)
new_arr.append(i)
return new_arr
arr_num = [1, 2, 3, 4, 5]
print(reverse_list(arr_num))
Or in short assign the reversed array to the new array
def reverse_list(arr = []):
new_arr = arr[::-1]
return new_arr
With a list comprehension together with the reversed build-in function (it returns a generator):
def reverse_list(lst):
return [v for v in reversed(lst)]
# or return list(reversed(lst))
Another version but without for-loop to highlight the underlying processes:
Using build-in function slice to select a range of items in a sequence object
and select an element from the container with __getitem__ subscription.
def reverse_list(lst):
# slice object
s = slice(None, None, -1)
# selection
return lst.__getitem__(s) # <--> lst[s]
you can simply use the reversed builtin function;
>>> reversed([1,2,3,4])
[4,3,2,1]
but if you wanted to have a function to return it, i will advise to use the slice indexing:
def rev_list(lst):
return lst[::-1]
Edit: Use backward indexing,
def rev(lst):
for i,x in enumerate(list(lst)):
lst[~i] = x
return lst
You can do it also by list comprehension:
def reverse(lst):
return [tmp[i] for i in range(0,len(lst)-1,-1)]

Making a list that returns the result with any index, despite "list out of range error"

I'm looking for some simple nifty solution that prevention "list out of range error" for list at all
For example
l = [1, 2, 3]
l[3] # 1, first element of the list
l[-4] # 3, last element of the list
I think that must be some class. I was very surprised when not found it in standard modules. For itertools there a cycle, but it is not quite that I want
Two solutions
1) use a proxy function to access the list
def my_getitem(l, key):
return l[key % len(l)]
l = [1, 2, 3]
my_getitem(l, 3) # 1
2) use a custom subclass of list which overloads subscript operator
class MyList(list):
def __getitem__(self, key):
return super().__getitem__(key % len(self))
l = MyList([1, 2, 3])
l[3] # 1
the above two code snippets effectively translates your cyclic indexes into ordinary list indexes.
You can write a function that does it for you
>>> def my_index(l, idx):
... return l[idx % len(l)] if l else None
...
>>> my_index(l,-4)
3
>>> my_index(l,3)
1
You could dynamically call it with yourlist[INDEX % (len(yourlist))]
Or you could create a function that does just the thing.
def fun(yourlist, INDEX):
return yourlist[ INDEX % (len(yourlist)) ]

Python inplace update of function arguments?

I am trying to create a function that updates arguments inplace (mostly for curiosity's sake):
def inplaceUpdate(f, inputs):
for i in inputs:
i = f(i)
I have three inputs:
x = 1
y = 2
z = 3
And the function f:
f = lambda i: i**2
I would like to run the following code:
inplaceUpdate(f, [x, y, z])
Then I would like for the values of x, y, and z to change inplace. Is this possible?
x = 1
y = 4
z = 9
In Python, integers are immutables. There's an on-topic question here.
The idea is that you cannot change the value of the references x, y and z. That means that if you do:
x = 2
y = 3
z = 4
some_func([x, y, z])
There's no way that some_func changes the value of the variables x, y, and z.
However, lists are mutable, and you could do:
def some_func(l):
l[:] = [i*2 for i in l]
l = [2, 3, 4]
some_func(l)
print l # the array has changed
And this would indeed change the list. This is because the operation l[:]=... assigns to the containment of the list, instead of reassigning the reference --that would be l=....
Seems, what you whant is to map a list. There is beautiful builtin function map for that
# Declare lambda somewhere
f = lambda i: i**2
# Map your inputs
input = [1, 2, 3]
result = map(f, input)
You can also use list comprehensions to achieve this. Its more pythonic than map, but does essentially the same thing.
input = [1, 2, 3]
ls = [x**2 for x in input]
There is no way to modify the values of the variables of the calling function with out using ugly hackery. If you saved a reference to the mutable list you created in [x,y,z], the inplaceUpdate function could modify it.
To accomplish this task using ugly hacks:
def inPlaceUpdate(inputs):
frame = sys._getframe(1)
for input in inputs:
i = f(input)
for k,v in frame.f_locals.iteritems():
if v == input:
frame.f_locals[k] = i
break
else:
for k,v in frame.f_globals.iteritems():
if v == input:
frame.f_globals[k] = i
break

How do you apply a list of lambda functions to a single element using an iterator?

I want to apply a list of lambda functions to a single element using an iterable that has to be created with yield.
The list of lambda functions would have something like:
[<function <lambda> at 0x1d310c8>, <function <lambda> at 0x1d355f0>]
And I want to apply every function, from left to right , to a single element using yield to construct an iterable to iterate the list
def apply_all(functions, item):
for f in functions:
yield f(item)
Example usage:
functions = [type, id, hex]
for result in apply_all(functions, 55):
print result
gives
<type 'int'>
20326112
0x37
Give this a shot:
def lambda_apply(unnamed_funcs, element):
for unnamed in unnamed_funcs:
yield unnamed(element)
>>> l = [lambda x: x**2, lambda x: 2*x]
>>> el = 5
>>> for y in lambda_apply(l, el):
... print y
...
25
10
Note that this works not only for a list of unnamed functions, but any list of functions of arity 1. This is because all functions, named or not, are first class objects in python. You can store them in a list, and use them later, as demonstrated above.
The answer could be formulated as
import numpy as np
def apply_funcs( funcs, val ):
for func in funcs:
yield func(val)
my_funcs = [lambda x: np.cos(x), np.sin, np.tan]
my_val = 0.1
for res in apply_funcs( my_funcs, my_val ):
print res
where the apply_funcs function does the trick and the rest is just for demonstration purposes.
Do you necessarily need a yield statement?
Because there is another way to create generator: to use ().
applied_it = (f(item) for f in functions)
def apply(value, lambda_list):
for function in lambda_list:
yield (function(value))

Python: how to create a function pointer with a set argument?

My problem:
Given the following:
def foo(a,b)
I am trying to call the python 'map' function while passing in a list for 'a' but use a set value for 'b.'
Another relevant fact is that 'b' is user input and thus, I cannot use the syntax:
def foo(a,b='default value')
I want my 'map' call to look like this:
map(foo_wrapper,list_for_a)
where 'foo_wrapper' is some function that takes in 'a' but uses the user specified 'b.'
I don't know whether function pointers can be specified this way and suspect that they cannot.
My solution to this problem uses globals, so if there's a more elegant way and the above is impossible, I will mark that as the answer as well.
Here is my solution in a nutshell:
b = ''
def foo(a,b):
print b,a
def foo_wrapper(a):
foo(a,b)
def main():
if sys.argv[1]:
a = ['John', 'Jacob', 'Jingle all the way']
global b
b = sys.argv[1]
map(foo_wrapper,a)
There may be a typo or two in the above; I am simplifying the problem from what I actually need to do.
Thanks for the replies!
You can use functools.partial() for this purpose:
from functools import partial
def f(a, b):
return a + b
x = range(10)
print map(partial(f, b=3), x)
prints
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
You want something akin to currying. You can just use lambda here:
map(lambda x: f(x,3), a)
Use a list comprehension or a generator expression
[f(x, your_set) for x in your_list]
If you don't need a list as a result, but just a lazy evaluated iterator, you can use a generator expression (or if you meant Python 3's map).
(f(x, your_set) for x in your_list)
Edit:
For your functions that would be:
L = ['John', 'Jacob', 'Jingle all the way']
[foo(a, b=b) for a in L]
List comprehensions are a syntax sugar to replace uses of map with lambda. If you have one of the following:
L2 = map(lambda arg: f(arg) + arg, L1)
L2 = map(lambda (x,y): x + y, L1)
L2 = map(lambda <arg>: <expression>, L1)
They can be rewritten as list comprehensions:
L2 = [f(arg) + arg for arg in L1]
L2 = [x + y for x, y in L1]
L2 = [<expression> for <arg> in L1]
Generator expressions are similar, but instead of a list they return a lazy iterator, and are written with parens instead of square brackets. (And because map in Python 3 is changed to not return lists, there its equivalent is a generator expression.) Sometimes a list is not need, for example when you want to do:
','.join(map(lambda x: x.upper(), L))
The equivalent list comprehension is:
','.join([x.upper() for x in L])
But you actually don't need a list, so you can simply do:
','.join(x.upper() for x in L)

Categories