Itertools for * arguments - python

I want to have a function to generate cross product of arbitrary number of arrays.
# Code to generate cross product of 3 arrays
M = [1, 1]
N = [2, 3]
K = [4, 5]
for M, N, K in itertools.product(M, N, K)
If I want to introduce a function using *, what is a good way to achieve that?
I tried the following code, but ended with an error: "TypeError: 'builtin_function_or_method' object is not iterable"
# def cross_product(*inputs):
return itertools.product(inputs)
cross_product(M, N, K)

You can actually just use unpacking without a helper function:
import itertools
L = [[1, 1],
[2, 3],
[4, 5]]
for x in itertools.product(*L):
print(x)

Related

Time limit while finding the duplicates in two lists

First argument is an integer array A of size N.
Second argument is an integer array B of size M.
Return an integer array denoting the common elements.
Input > A = [1, 2, 2, 1], B = [2, 3, 1, 2], out > [1, 2, 2]
Input > A = [2, 1, 4, 10], B = [3, 6, 2, 10, 10], out > [2, 10]
Code is below I got the proper out, but for higher number of elements i m getting errror
def solve(A, B):
result = []
for element in A:
if element in B:
result.append(element)
B.remove(element)
return result
DO i need to do generator yield functionality for this
Membership tests of a list with the in operator cost O(n) in time complexity. You can improve the efficiency by converting the list to a collections.Counter object first to improve the time complexity of membership lookups to O(1):
from collections import Counter
def solve(A, B):
B = Counter(B)
result = []
for element in A:
if element in B:
result.append(element)
B -= {element: 1}
return result
In fact, collections.Counter offers the intersection operator (&) just for this purpose:
def solve(A, B):
return list((Counter(A) & Counter(B)).elements())

Sticky index reference while inserting into 2D list in Python

While attempting to implement a function that produces all permutations given a list of integers, I'm seeing this behavior where the inserts are not occurring as expected.
My code:
def permute(nums):
perms = [[]]
for i in range(len(nums)):
new_perms = perms * (i + 1)
for j in range(len(new_perms)):
new_perms[j].insert(j % len(perms), nums[i])
perms = new_perms
return perms
When calling permute([1, 2, 3]) I'm expecting the perms to grow like:
[[]]
[[1]]
[[2, 1], [1, 2]
[[3, 2, 1], [1, 3, 2], [2, 1, 3], [3, 1, 2], [2, 3, 1], [1, 2, 3]
However, by the second iteration of the interior loop with new_perms: [[1], [1]] I'm expecting it to grow to [[2, 1], [1, 2]], instead I'm getting [[2,1],[2,1]] and then [[2,2,1],[2,2,1]]. On each iteration of the j loop, the number is getting inserted into the current j position of all values of the list simultaneously on each iteration. Not what I was trying to do or expecting.
Ultimately, the code outputs:
[[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1],[3,3,3,3,3,3,2,2,1]]
Either this is some subtle reference behavior (yay, learn something new!) or I'm just having a really dumb day ;) Any help appreciated.
PLEASE NOTE: I'm NOT asking for help with an alternate or optimal permutations function! I'm trying to figure out why this particular code is behaving in an unexpected way. Thank you.
Ok, learned a good one here. DEEPCOPY!
import copy
def permute(nums):
perms = [[]]
for i in range(len(nums)):
len_perms = len(perms)
old_perms = perms
perms = []
for _ in range(i+1):
perms += copy.deepcopy(old_perms)
for j in range(len(perms)):
perms[j].insert(j // len_perms, nums[i])
return perms

What makes function composition so powerful?

I have read about functional programming and it's core concept seem to be the high use of immutable datastructures, which in turn lead to pure functions. These pure functions ought be easily composable like in this example:
def add(x, y):
return 3 + 3
def minus1(z):
return z - 1
print(minus1(add(3,3)))
I understand, that i can compose functions and build new functions by this method. In the following example, i have composed two impure functions:
def add_list_last(arr):
arr.append(1)
return arr
def insert_entry_at_start(arr):
arr.insert(0,1)
return arr
print(add_list_last(insert_entry_at_start([1,2,3])))
Why can't i just compose impure functions like i did in the second example and why is it so powerful? What is the disadvantage of the second example and why is the mutation of the array preventing composability?
T = TypeVar('T')
def split(v: T) -> Tuple[T, T]:
return v, v
def apply_to_first(f: Callable[[T], T], *xs: T) -> Sequence[T]:
return (f(xs[0]), *xs[1:])
apply_to_first(insert_entry_at_start, *split([1, 2]))
You would expect this result here:
([1, 2, 1], [1, 2])
But in fact you get:
([1, 2, 1], [1, 2, 1])
Because insert_entry_at_start is impure.
Here's a simplified example:
def prepend_impure(lst, element):
lst.insert(0, element)
return lst
def prepend_pure(lst, element):
cpy = lst[:]
cpy.insert(0, element)
return cpy
def combine(list1, list2):
return [i + j for i, j in zip(list1, list2)]
list1 = [2, 3, 4]
list2 = [2, 3, 4]
print(combine(prepend_impure(list1, 1), prepend_impure(list1, 1)))
print(combine(prepend_pure(list2, 1), prepend_pure(list2, 1)))
Output:
[2, 2, 4, 6, 8]
[2, 4, 6, 8]
The prepend functions insert an element at the beginning of a given list and return the list.
The combine function adds 2 lists together.
Personally, I would expect the code to both return lists of [1, 2, 3, 4] and add the 2 together.
Not only do you not get what you expect with the impure version.. In a large codebase, trying to be mindful of all the ways a function can mutate or modify your objects can produce a lot of cognitive overload.

Indexing nested list by a list

given a nested list like
>>> m= [[3, 1], [2, 7]]
I can get an element like this
>>> m[1][0]
2
How can i get the same value if the index is given in a list, i.e. as [1, 0]?
I am looking for something that the Q programming language offers with dot like in code below
q) m: (3 1; 2 7)
q) m[1][0]
2
q) m . 1 0
2
As a quick-n-dirty solution, you can abuse functools.reduce like this:
from functools import reduce
def get_recursive(lst, idx_list):
return reduce(list.__getitem__, [lst, *idx_list])
>>> y = [[3, 1], [2, 7]]
>>> get_recursive(y, [0, 1])
1
>>> get_recursive(y, [1, 0])
2
There are quite a few corner cases to handle (plus you'd have to be sure the path exists or else handle any errors that arise) but this should get you started.
just define a recursive function that takes the index of the passed list, then passes this index and the sliced index list to itself, until the sliced index list is empty:
def get(m,l):
if not l:
return m
return get(m[l[0]],l[1:])
print(get([[3, 1], [2, 7]],[1,0]))
prints: 2
You can convert to NumPy array first:
import numpy as np
m = [[3, 1], [2, 7]]
np.array(m)[1,0]
Output:
2
This solution requires imports, but only from the standard library. Very similar to #cs95's solution, but slightly cleaner in my view.
from functools import reduce
from operator import getitem
nested_list = [[[['test'], ['test1']], ['test2']], ['test3', 'test4']]
indices = [0, 1, 0]
assert reduce(getitem, indices, nested_list) == 'test2'

passing list of lists to a function

I have a list [0.2, [1, 1.3], [1, 0.5, 2.1] ...] and need to pass this list as an argument in a function and I should be able to access elements in the called function, kindly help with code or hints to do this. Thanks in advance
def func(list):
#calculate opt_p using list
return(opt_p)
def metric(metric, K, N):
opt_p=[]
creating a sequence such that(alpha is my variable name)
alpha_0 = [0.2] has one element
alpha_1 = [1, 1.3] two elements
alpha_2 = [1, 0.5, 2.1] three elements ... upto alpha N suchthat last element has N elements
temp=func(alpha) #HERE IS THE ERROR *Invalid syntax
opt_p.append(func(temp))
def main():
metric(12, 5, 8)
if __name__ == '__main__':
main()
Maybe I'm understanding something wrong, but looks like you forgot the
opt_alpha = [alpha_0, alpha_1, alpha_2]
line just before the error.
When the func is invoked, the opt_alpha in not known.
By the way you miss the i value.
My advice is: try to read the code once more. The first think that's being run is if __name__. Then the main function. Then the metric and then the func. Follow your variables. If you're not used to debugging in your mind, take a pen, some paper and write all the values of variables step by step. In a minute you'll see, where were the mistakes.
EDIT:
Due to commment:
Look at this example.
>>> a = [1, 2, 3]
>>> b = [2, 3, 4]
>>> c = [3, 4, 5]
>>> l = [a, b, c]
>>> l
[[1, 2, 3], [2, 3, 4], [3, 4, 5]]
>>> def f(l):
... for element in l:
... print element
... print "--", l[2][1]
...
>>> f(l)
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
-- 4
>>>
There is no philosophy of passing list of lists to function. You simply... do it.
I think you just have a syntax confusion. If alpha is the variable then it should be set like so
alpha = [[] for x in range(0,3)]
alpha[0] = [list]
alpha[1] = [other list]
...
func(alpha)
and as noted you have not defined 'i' so it will be created in the function call.

Categories