difference in product using two different ways in python - python

I am experiencing a weird issue in finding the product of some numbers in two different ways. Example below. Can someone explain why the first method is not giving the correct answer?
Method 1:
arr = [[1, 2, 3]]*34
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
np.prod([len(x) for x in arr])
-217042295
Method 2:
pr = 1
for x in arr: pr = pr*len(x)
pr
16677181699666569
Thank you.

This happens because your numpy (I assume np is short for numpy) uses 32-bit integers.
That happens either because that is somehow the default for your computer, or because you configured numpy to use int32 as the default dtype for these operations. You can manually control this by providing np.prod with dtype=np.int64 to get the correct result.
>>> import numpy as np
>>> arr = [[1,2,3]] * 34
>>> np.prod([len(x) for x in arr], dtype=np.int32)
-217042295
>>> np.prod([len(x) for x in arr], dtype=np.int64)
16677181699666569
>>>

Related

How to combine lists in list accordingly. (without numpy)

I have list of lists of lists and need to combine the inner lists accordingly.
For example:
1. mylist=[[[1]], [[2]]]
2.
mylist= [[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
[[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
(in short-[[[1]*3]*4, [[2]*3]*4, [[3]*3]*4])
Expected output-
[[[1, 2]]]
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
(in short-[[[1, 2, 3]]*3]*4)
This is what I have untill now-
def combine_channels(mylist):
elements = [[] for _ in range(len(mylist[0]))]
for l1 in mylist:
for idx, l2 in enumerate(l1):
elements[idx] += l2
return [elements]
The problem is that the output is (for input example 2)-
[[[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3],
[1, 1, 1, 2, 2, 2, 3, 3, 3]]]
and not-
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]],
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
mylist = [[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]],
[[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]],
[[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
def combine_channels(mylist):
def list_zip(_list):
return list(zip(*_list))
elements = []
for l in list_zip(mylist):
elements.append(list_zip(l))
return elements
combine_channels(mylist)

how to merge lists in list (without numpy)

This is what i have-
def merge_list(mylist)
list1 = []
one_len = len(mylist)
two_len = len(mylist[0][0])
for index in range(two_len):
combine_list = []
for index2 in range(one_len):
combine_list.extend([a[index] for a in mylist[
index2]])
list1.append(combine_list)
return list1
But i have a problem with the output-
for example:
input-
mylist=[[[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]], [[2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2]], [[3, 3, 3], [3, 3, 3], [3, 3, 3], [3, 3, 3]]]
in short-
[[[1]*3]*4, [[2]*3]*4, [[3]*3]*4]
the output is -
[[[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3], [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]]]
and not -
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
in short-
[[[1, 2, 3]]*3]*4
I would be happy to solve the problem and advise how to shorten the code.
In order to fix your code, you just need to update the return statement like this:
return [list1]
Though there is still a hidden problem when your inner lists lengths are longer than one element. Check your outputs with sample inputs like [[[2,1], [3,1]]].
One further - more compact - solution may be obtained by concatenating the inner lists within a cycle, then recreate the number of dimensions you need, moving the complexity from O(n^2) to O(n).
mylist = [[[2,1]],[[3,1]]]
def merge_list(mylist):
l_out = []
for l in mylist:
l_out += l[0]
return [[l_out]]
EDIT: In case of more complex inputs, you can extract first all elements and eventually fix the dimensions. This will still bring O(n^2) complexity though:
def merge_list(lst):
elements = [[] for _ in range(len(mylist[0]))]
for l1 in mylist:
for idx, l2 in enumerate(l1):
elements[idx] += l2
return [elements]
merge_list(mylist)
Input:
[[[1], [1]], [[2], [2]], [[3], [3]]]
Output:
[[[1, 2, 3], [1, 2, 3]]]

Python group list into subgroups with constraints

I really searched for this one, because I am almost certain some variation has been asked before but I couldn't put in the correct terms into Google to get a result that matches what I am trying to do. Generally seems like people are looking for the total combinations without constraints.
I am trying to do the following:
Given a list like this:
[1, 1, 2, 2, 3, 3] group it into as many groups of [1, 2, 3] as possible
So
[1, 1, 2, 2, 3, 3] -> [[1, 2, 3], [1, 2, 3]]
[1, 1, 2, 3, 3] -> [[1, 2, 3], [1, 3]]
[1, 1, 3, 3, 5] -> [[1, 3, 5], [1, 3]]
[1, 4, 4, 7] -> [[1, 4, 7], [4]]
Notes:
Input will always be sorted, but the values of these numbers is not known, so it will need to work in general sense.
The idea is I have objects with certain attributes that need to be grouped together to create a different object, but sometimes I am given repeats (and potentially incomplete repeats) -- ie, I used to think that the attributes of my objects will always just be [1, 2, 3] but turns out sometimes I can get [1, 1, 2, 2, 3, 3] and I need a way to break that into two [1, 2, 3] lists to create an intermediate object downstream.
You can use zip_longest and groupby from itertools:
from itertools import zip_longest, groupby
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [[j for j in i if j is not None] for i in z]
Usage:
>>> f([1, 1, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3]]
>>> f([1, 1, 2, 3, 3])
[[1, 2, 3], [1, 3]]
>>> f([1, 1, 3, 3, 5])
[[1, 3, 5], [1, 3]]
>>> f([1, 4, 4, 7])
[[1, 4, 7], [4]]
# Update
>>> f(sorted([1, 1, 2, 2, 3, 3, 1, 2]))
[[1, 2, 3], [1, 2, 3], [1, 2]]
# Update 2
>>> f([1, 1, 1, 2, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3], [1, 2]]
Update
Alternative version suggested by #cards using filterfalse:
from itertools import zip_longest, groupby, filterfalse
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [list(filterfalse(lambda j: j is None, i)) for i in z]

generate all k-Permutations from n+1 without recalculate the k-permutations from n python 3

My task is to calculate the k-permutations from the updated List by new element
without recalculating the k-permutations already gotten from the previous state of the list. Example:
liste = [1, 2, 3]
3-permutations are:
[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]
The updated list:
liste = [1, 2, 3, 4]
I would like to obtain directly 3-permutations[1, 2, 3, 4]-3-permutations[1, 2, 3]
without recalculating 3-permutations[1, 2, 3]
Calculate directly the new permutations:
[1, 2, 4], [1, 3, 4], [1, 4, 2], [1, 4, 3], [2, 1, 4], [2, 3, 4], [2, 4, 1],
[2, 4, 3], [3, 1, 4], [3, 2, 4], [3, 4, 1], [3, 4, 2], [4, 1, 2], [4, 1, 3],
[4, 2, 1], [4, 2, 3], [4, 3, 1], [4, 3, 2]
Thanks
Computing first the cartesian product {0,1,2,3}x{0,1,2}x{0,1} and taking the nth element of list (1,2,3,4).
r=[]
for prd in itertools.product([[0,1,2,3],[0,1,2],[0,1]]):
l=[1,2,3,4]
r0=[]
for i in prd:
r0 += l[i]
del l[i]
r += r0
EDIT: original answer gives the 3-permutations of [1,2,3,4]
following command answers specifically to question, see how it can be generalized
[list(j) for i in itertools.combinations([1,2,3],2) for j in itertools.permutations(list(i)+[4])]
next case, maybe one of ?
[list(j) for i in itertools.combinations([1,2,3],2) for j in itertools.permutations(list(i)+[4,5])]
[list(j) for i in itertools.combinations([1,2,3,4],3) for j in itertools.permutations(list(i)+[4,5])]
try saving the existing permutations to a list, then do:
if newPermutation not in listOfExistingPermutations:
listOfExistingPermutations.append(newPermutation)
or something along those lines

python-AttributeError: 'NoneType' object has no attribute 'remove'

I have a 3D list in python like:
features= [ [[1,2,3],[1,2,3],[1,2,3]] ,None , [[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3]], None,None,[[1,2,3],[1,2,3],[1,2,3]] ]
I expect to see:
features=[ [[1,2,3],[1,2,3],[1,2,3]] ,[[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3]] ,[[1,2,3],[1,2,3],[1,2,3]] ]
When I try to remove None using the following code:
for i in range(len(features)):
if features[i]==None:
features[i].remove()
It produces the error :
AttributeError: 'NoneType' object has no attribute 'remove'
If I try this:
for i in range(len(features)):
if features[i]==None:
del features[i]
It produces error:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Lastly I tried this code:
for i in range(len(features)):
if features[i]==None:
features[i]=filter(None,features[i])
It produced the error :-
TypeError: 'NoneType' object is not iterable
How can I fix this error?
In your first code block, you are not passing a value to be removed from the list. In the second code block, you are altering the list while iterating, thus producing a skewed index-vs-value location. The best way is to filter out the Nones from the list:
features= [ [[1,2,3],[1,2,3],[1,2,3]] ,None , [[1,2,3],[1,2,3],[1,2,3]],
[[1,2,3],[1,2,3],[1,2,3]], None,None,[[1,2,3],[1,2,3],[1,2,3]] ]
final_features = list(filter(lambda x:x is not None, features))
Output:
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
Create a list comprehension and only keep the values if the index is not None, it will keep your sub-lists intact:
features = [[[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
>>> print features
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], None, None, [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
>>> print [f for f in features if f is not None]
[[[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]], [[1, 2, 3], [1, 2, 3], [1, 2, 3]]]
Short and simple:
features_x = list(filter(None, features))
print(features_x)
See a demo on ideone.com.
Like willem says you should never alter a list that you're iterating over. The correct way of doing is to create a new list. You can do that with a list comprehension in the following way.
New = [item for item in mylist if item is not None]
You could also try it this way:
new_features = []
for f in features:
if f is not None:
new_features.append(f)
You can also just index through the array backwards when you do your features[i].remove().
for i in reversed(range(len(features))):
if features[i]==None:
features[i].remove()
This way you are not removing array items out from underneath your index.
The other answers are slick-code, no doubt, but this is the easiest simple-code solution.
Of course, you should never alter a list you are iterating through as a general best-practice, but when you absolutely have to keep using the same list, this will work.

Categories

Resources