numpy. Sum multidimensional array at specific indexes - python

I'm trying to replace something like this code, for a vectorized efficient operation using numpy.
counter = 0
idxs = [1, 3]
lists = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
for l in lists:
for idx in idxs:
counter += l[idx]

Just sum the array:
idxs = [1, 3]
lists = [[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]
ary = np.array(lists)
counter = ary[:,idxs].sum()

Related

Create a matrix in Python with sequences increasing

I am working on a project and I need to be able to create a function that takes in a value (n) and returns a matrix with increasing values.
ex: Given x = 2, return = [[1],[1, 2]]
Given x = 5, return = [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4],[1, 2, 3, 4, 5]]
Below is what I have thus far:
def matrixIncrease(n):
lst = []
for i in range(n):
lst.append([])
for j in range(0, n):
lst[i].append(j)
return lst
print(matrixIncrease(3))
This will just return
[[0, 1, 2], [0, 1, 2], [0, 1, 2]]
So it looks like the correct amount of inner list are being created. But, the values inside the list are not increasing correctly. Any suggestions?
Maybe you could try this List Comprehension way:
It's quite self-explnatory in the code, just play/experiment with different i and j to see the effects of changes...
Basically the j is to iterate and increase the numbers in each loop.
def create_sub(n):
''' create n sub_lists: each list has increasing items:
[1], [1, 2], [1, 2, 3], .... [1, ... n] '''
sub_matrix = [[j +1 for j in range(0, i)] # j - for col values
for i in range(1, n + 1)] # i - control rows
return sub_matrix
>>>create_sub(5)
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
>>>create_sub(8)
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8]]
You could try this:
all_ = []
def matrixIncrease(n):
if n == 1:
all_.append([1])
return[1]
j=[]
for i in range(1,n+1):
j.append(i)
matrixIncrease(n-1)
all_.append(j)
matrixIncrease(7)
print(all_)

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

Count odds in list of lists

What would be the shortest way to count the number of odd numbers in a list of lists like this with arbitrary dimensions, not necessarily 5x5:
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
I tried, but i'd guess there's shorter:
counter = 0
for row in list_of_lists:
for i in row:
if i % 2 != 0:
counter += 1
print(counter)
If you always have one level of flat lists inside the main list you can use an inner loop to flatten, summing the result of each i % 2 which will be 1 for odd and 0 for even numbers:
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
print(sum(i % 2 for sub in list_of_lists for i in sub))
Or use itertools.chain to do the flattening:
from itertools import chain
print(sum(i % 2 for i in chain(*list_of_lists)))
If you had arbitrary nesting, recursion would be an easy way to approach the problem:
def flat(lst):
for i in lst:
if isinstance(i, list):
for j in flat(i):
yield j % 2
else:
yield i % 2
print(sum(flat(list_of_lists)))
The numpy way of counting for a contrast:
import numpy as np
list_of_lists = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
l = np.array(list_of_lists)
print len(l[l%2!=0])
l[l%2!=0] returns all the elements that satisfy the condition l%2!=0 and len() counts it.
PS : This of course assumes that the list_of_lists is rectangular. For a solution that allows different length for each inner-list, see Padraic's answer.

How to make a set of lists

I have a list of lists like this:
i = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
I would like to get a list containing "unique" lists (based on their elements) like:
o = [[1, 2, 3], [2, 4, 5]]
I cannot use set() as there are non-hashable elements in the list. Instead, I am doing this:
o = []
for e in i:
if e not in o:
o.append(e)
Is there an easier way to do this?
You can create a set of tuples, a set of lists will not be possible because of non hashable elements as you mentioned.
>>> l = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
>>> set(tuple(i) for i in l)
{(1, 2, 3), (2, 4, 5)}
i = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
print([ele for ind, ele in enumerate(i) if ele not in i[:ind]])
[[1, 2, 3], [2, 4, 5]]
If you consider [2, 4, 5] to be equal to [2, 5, 4] then you will need to do further checks
You can convert each element to a tuple and then insert it in a set.
Here's some code with your example:
tmp = set()
a = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
for i in a:
tmp.add(tuple(i))
tmp will be like this:
{(1, 2, 3), (2, 4, 5)}
Here's another way to do it:
I = [[1, 2, 3], [2, 4, 5], [1, 2, 3], [2, 4, 5]]
mySet = set()
for j in range(len(I)):
mySet = mySet | set([tuple(I[j])])
print(mySet)

Categories

Resources