Cartesian product using python without itertools - python

I came across this nice line of python code for cartesian product of n number of lists that I would like to bring back on multiple lines :
def cart_product_1(*seqs):
if not seqs:
return [[]]
else:
return [[x] + p for x in seqs[0] for p in cart_product_1(*seqs[1:])]
This seemed pretty straightforward to me, but obviously I'm missing something here. I'm thinking I need to append a list somewhere but can't quite figure it out.
def cart_product_1(result,*seqs):
if not seqs:
return [[]]
else:
for x in seqs[0]:
for p in cart_product_1(result,*seqs[1:]):
result.append([x]+p)
return result
This leads to a MemoryError.

The line in your example is a list comprehension. Basically, the one line is constructing a list and calculating its members.
To do the same thing, you have to add an initializer and return:
result = []
for x in seqs[0]:
for p in cart_product_1(*seqs[1:]):
result.append([x]+p)
return result

Related

Make list out of list comprehension using generator

I've been trying to turn the output of my list comprehension into a variable. Quite silly, but no matter what I try, I seem to end up with an empty list (or NoneType variable).
I'm guessing it has something to do with the generator that it uses, but I'm not sure how to get around it as I need the generator to retrieve the desired results from my JSON file. (And I'm too much of a list comprehension and generator newbie to see how).
This is the working piece of code (originally posted as an answer to these questions (here and here)).
I'd like the output of the print() part to be written to a list.
def item_generator(json_Response_GT, identifier):
if isinstance(json_Response_GT, dict):
for k, v in json_Response_GT.items():
if k == identifier:
yield v
else:
yield from item_generator(v, identifier)
elif isinstance(json_Response_GT, list):
for item in json_Response_GT:
yield from item_generator(item, identifier)
res = item_generator(json_Response_GT, "identifier")
print([x for x in res])
Any help would be greatly appreciated!
A generator keeps its state, so after you iterate through it once (in order to print), another iteration will start at the end and yield nothing.
print([x for x in res]) # res is used up here
a = [x for x in res] # nothing left in res
Instead, do this:
a = [x for x in res] # or a = list(res)
# now res is used up, but a is a fixed list - it can be read and accessed as many times as you want without changing its state
print(a)
res = [x for x in item_generator(json_Response_GT, "identifier")] should do the trick.

Recursively generating a list of lists in a triangular format given a height and value

I recently started looking into recursion to clean up my code and "up my game" as it were. As such, I'm trying to do things which could normally be accomplished rather simply with loops, etc., but practicing them with recursive algorithms instead.
Currently, I am attempting to generate a two-dimensional array which should theoretically resemble a sort of right-triangle in an NxN formation given some height n and the value which will get returned into the 2D-array.
As an example, say I call: my_function(3, 'a');, n = 3 and value = 'a'
My output returned should be: [['a'], ['a', 'a'], ['a', 'a', 'a']]
[['a'],
['a', 'a'],
['a', 'a', 'a']]
Wherein n determines both how many lists will be within the outermost list, as well as how many elements should successively appear within those inner-lists in ascending order.
As it stands, my code currently looks as follows:
def my_function(n, value):
base_val = [value]
if n == 0:
return [base_val]
else:
return [base_val] + [my_function(n-1, value)]
Unfortunately, using my above example n = 3 and value = 'a', this currently outputs: [['a'], [['a'], [['a'], [['a']]]]]
Now, this doesn't have to get formatted or printed the way I showed above in a literal right-triangle formation (that was just a visualization of what I want to accomplish).
I will answer any clarifying questions you need, of course!
return [base_val]
Okay, for n == 0 we get [[value]]. Solid. Er, sort of. That's the result with one row in it, right? So, our condition for the base case should be n == 1 instead.
Now, let's try the recursive case:
return [base_val] + [my_function(n-1, value)]
We had [[value]], and we want to end up with [[value], [value, value]]. Similarly, when we have [[value], [value, value]], we want to produce [[value], [value, value], [value, value, value]] from it. And so on.
The plan is that we get one row at the moment, and all the rest of the rows by recursing, yes?
Which rows will we get by recursing? Answer: the ones at the beginning, because those are the ones that still look like a triangle in isolation.
Therefore, which row do we produce locally? Answer: the one at the end.
Therefore, how do we order the results? Answer: we need to get the result from the recursive call, and add a row to the end of it.
Do we need to wrap the result of the recursive call? Answer: No. It is already a list of lists. We're just going to add one more list to the end of it.
How do we produce the last row? Answer: we need to repeat the value, n times, in a list. Well, that's easy enough.
Do we need to wrap the local row? Answer: Yes, because we want to append it as a single item to the recursive result - not concatenate all its elements.
Okay, let's re-examine the base case. Can we properly handle n == 0? Yes, and it makes perfect sense as a request, so we should handle it. What does our triangle look like with no rows in it? Well, it's still a list of rows, but it doesn't have any rows in it. So that's just []. And we can still append the first row to that, and proceed recursively. Great.
Let's put it all together:
if n == 0:
return []
else:
return my_function(n-1, value) + [[value] * n]
Looks like base_val isn't really useful any more. Oh well.
We can condense that a little further, with a ternary expression:
return [] if n == 0 else (my_function(n-1, value) + [[value] * n])
You have a couple logic errors: off-by-1 with n, growing the wrong side (critically, the non-base implementation should not use a base-sized array), growing by an array of the wrong size. A fixed version:
#!/usr/bin/env python3
def my_function(n, value):
if n <= 0:
return []
return my_function(n-1, value) + [[value]*n]
def main():
print(my_function(3, 'a'))
if __name__ == '__main__':
main()
Since you're returning mutable, you can get some more efficiency by using .append rather than +, which would make it no longer functional. Also note that the inner mutable objects don't get copied (but since the recursion is internal this doesn't really matter in this case).
It would be possible to write a tail-recursive version of this instead, by adding a parameter.
But python is a weird language for using unnecessary recursion.
The easiest way for me to think about recursive algorithms is in terms of the base case and how to build on that.
The base case (case where no recursion is necessary) is when n = 1 (or n = 0, but I'm going to ignore that case). A 1x1 "triangle" is just a 1x1 list: [[a]].
So how do we build on that? Well, if n = 2, we can assume we already have that base case value (from calling f(1)) of [[a]]. So we need to add [a, a] to that list.
We can generalize this as:
f(1) = [[a]]
f(n > 1) = f(n - 1) + [[a] * n]
, or, in Python:
def my_function(n, value):
if n == 1:
return [[value]]
else:
return my_function(n - 1, value) + [[value] * n]
While the other answers proposed another algorithm for solving your Problem, it could have been solved by correcting your solution:
Using a helper function such as:
def indent(x, lst):
new_lst = []
for val in lst:
new_lst += [x] + val
return new_lst
You can implement the return in the original function as:
return [base_val] + indent(value, [my_function(n-1, value)])
The other solutions are more elegant though so feel free to accept them.
Here is an image explaining this solution.
The red part is your current function call and the green one the previous function call.
As you can see, we also need to add the yellow part in order to complete the triangle.
These are the other solutions.
In these solutions you only need to add a new row, so that it's more elegant overall.

Finding the Dot Product of two different key-value lists within a single dictionary

I am using this method to create a dictionary where the keys are Names which are paired with a list of values
def create_voting_dict(strlist):
return {line.split()[0]:[int(x) for x in line.split()[3:]] for line in strlist}
However, now I have to take the dot product of the values of two keys found in the dictionary.
This new problem begins as follows:
def policy_compare(sen_a, sen_b, voting_dict):
I am having issues trying to find what to return in this situation.
Any help is welcome! Thanks in advance!
Oh! An example of an expected outcome would look like this:
...voting_dict = {'Fox-Epstein':[-1,-1,-1,1],'Ravella':[1,1,1,1]}
...policy_compare('Fox-Epstein','Ravella', voting_dict)
...-2
I hope this is what you need.
def create_voting_dict(strlist):
return {line.split()[0]:[int(x) for x in line.split()[3:]] for line in strlist}
def dot(K, L):
if len(K) != len(L):
return 0
return sum(i[0] * i[1] for i in zip(K, L))
def policy_compare(sen_a, sen_b, voting_dict):
return dot(voting_dict[sen_a], voting_dict[sen_b])
voting_dict = {'Fox-Epstein':[-1,-1,-1,1],'Ravella':[1,1,1,1]}
print(policy_compare('Fox-Epstein','Ravella', voting_dict))
It returns -2.

Powerset recursive, list comprehension python3

I'm new to Python3 and are trying to do a recursive powerset function. It should use list comprehension.
I wrote:
def powerset(seq):
if not seq:
return [[]]
return powerset(seq[1:]) + [[seq[0]] + n for n in powerset(seq[1:])]
This function works but I got feedback and was told it was unnecessary to call the function two times. It did to much computing. It should easily be able to compute up to 20 powersets. So how should I do? I can't get it to work without calling the function twice. Thanks.
Just calculate powerset(seq[1:]) once, store it in a variable, and use it twice:
def powerset(seq):
if not seq:
return [[]]
ps = powerset(seq[1:])
return ps + [[seq[0]] + n for n in ps]
The difference to yours is that this way, you use ps twice, but you compute it just once.
Alternatively, you could use a double list-comprehension (if you like that sort of thing...)
def powerset(seq):
return [x for ps in powerset(seq[1:]) for x in ([seq[0]] + ps, ps)] if seq else [[]]
Here, the same temporary variable ps is defined inside the list comprehension. Note, however, that the results will be in a slightly different order this way.
I feel very unclear. I actually don't understand how just assigning it to a variable can change that? It means the same thing?
You seem to think too much in terms of pure math here. In programming, y = f(x) does not mean "y is the same as/synonymous for f(x)", but "assign the result of f(x) to y".

python recursion on list of lists without isinstance (different)

I have an arbitrary list of arbitrary (but uniform) lists of numbers. (They are the boundary coordinates of bins in an n-space whose corners I want to plot, but that's not important.) I want to generate a list of all the possible combinations. So: [[1,2], [3,4],[5,6]] produces [[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5]...].
Can anyone help me improve this code? I don't like the isinstance() call, but I can't figure out a more python-ish way to append the elements on the first pass, when the first arg (pos) is a list of numbers as opposed to a list of lists.
def recurse(pos, vals):
out = []
for p in pos:
pl = p if isinstance(p,list) else [p]
for x in vals[0]:
out.append(pl + [x])
if vals[1:]:
return recurse(out, vals[1:])
else:
return out
a = [[1,2,3],[4,5,6],[7,8,9],[11,12,13]]
b = recurse(a[0], a[1:])
Thank you.
From your example it seems all you want is
from itertools import product
a = [[1,2,3],[4,5,6],[7,8,9],[11,12,13]]
print list(product(*a))
Try with the itertools.product
import itertools
a = [[1,2,3],[4,5,6],[7,8,9],[11,12,13]]
iterator = itertools.product(*a)
result = [item for item in iterator.next()]
To be more pythonic you have don't want to do type checking. Python is all about duct typing. What happens if you pass a tuple to the function (which should be more efficient).
You could try
if type(p) != list:
try:
p = list(p)
except TypeError:
p = [p]
pl = p
When there is a library/module that does what you want, you should opt use it (+1 to all those who mentioned itertools.product). However, if you're interested in an algorithm to accomplish this, you are looking for a class of algorithms called recursive descent
answer = []
def recurse(points, curr=[]):
if not points:
answer.append(curr)
curr = []
return
else:
for coord in points[0]:
recurse(points[1:], curr+[coord])

Categories

Resources