Python get index of class list on condition - python-3.x

I have the following code:
import numpy as np
np.random.seed(1)
class Order:
def __init__(self, amount, orderId):
self.orderId = orderId
self.amount = amount
n = 5
amounts = np.random.randint(low=8, high=20, size=n)
orderIds = np.arange(n)
orders = [Order(amounts[i],orderIds[i]) for i in range(n)]
And I would like to get a list of orderId for all orderId when the cumulative sum of amount of the sorted list if above some threshold.
Example:
orderIds = [0, 1, 2, 3, 4]
amounts = [15, 18, 19, 16, 10]
descending_ordered_amounts = [19, 18, 16, 15, 10]
cumsum = [19, 37, 52, 68, 78]
threshold = 55
cumsum > threshold # [False, False, False, True, True]
Then I would like to get Ids = [0,4]
What would be the fastest way to get that please?

The main problem here is to sort the ids along the values so you know what to return.
It can be done by something like this, using a intermediate value to hold a tuple of amounts and ids.
orderIds = [0, 1, 2, 3, 4]
amounts = [15, 18, 19, 16, 10]
des = [(x, y) for x, y in zip(amounts, orderIds)]
des.sort(key=lambda x: x[0], reverse=True)
sortedIds = np.array([x[1] for x in des])
threshold = 55
ids = np.cumsum([x[0] for x in des]) > threshold
print(sortedIds[ids])
that will print the ids that satisfy the requirement. i did not use a variable descending_ordered_amounts, since it is stored on the first column of des, so i just used a list comprehension in cumsum

Related

Sorting lists of floats

I would like to sort the list s and in the same manner the list s1. The code below workers for integers (after changing 2.2 to 2 and 20.6 to 20). How to adjust the code for floats, please?
s = [2.2, 3, 1, 4, 5, 3]
s1 = [20.6, 600, 10, 40, 5000, 300]
res = []
for i in range(len(s1)):
res0 = s1[s[i]]
res.append(res0)
print(res)
print('Sorted s:', sorted(s))
print('Ind:', sorted(range(len(s)), key=lambda k: s[k]))
print('s1 in the same manner as s:', res)
There is actually an error related with a part of your code res0 = s1[s[i]] that pops up:
list indices must be integers or slices, not float.
Supposed that the index is 0: s1[s[0]] -> s[0] == 2.2 -> s1[2.2]
Your code is actually using the values of s as an index for each value of s1. Your code wouldn't be able to sort a list by the manner of another list regardless if the list contains integers only.
Instead, you should add two new arrays:
s_index_list = sorted(range(len(s)), key=lambda k: s[k])
s1_sorted = sorted(s1)
One which contains the index of each value of s (Reference to this answer https://stackoverflow.com/a/7851166/18052186), and another which sort s1.
Then, you replace this bit of your code.
res0 = s1[s[i]]
by
res0 = s1_sorted[s_index_list[i]]
That way, you can sort the list s1 in the same manner as s by actually associating a value of s1 with an index from s. The result would have been:
[40, 10, 20.6, 5000, 300, 600]
Sorted s: [1, 2.2, 3, 3, 4, 5]
Ind: [2, 0, 1, 5, 3, 4]
s1 in the same manner as s: [40, 10, 20.6, 5000, 300, 600]

Sum values in a list one by one, check for any step if the sum is equal to 0 and store values contributing to the sum to a new list Python 3.x

I have a list like this:
my_list = [-1, 5, 6, -7, -3, 7, 9, -8, 4, -12, ....., N]
Using Python 3.x, I would like to sum numbs one by one and check at each step if the sum is equal to zero. If it is not continue, otherwise break and store values contributing to the sum (when sum = 0) in a new list.
For now, I'm not considering problems regarding performance.
Can you please help me?
Really appreciate your help!
If I understood correctly, you want to sum up your items until the sum is different from 0 and also save this numbers in another list.
You can do it like this
my_list = [-1, 5, 6, -7, -3, 7, 9, -8, 4, -12]
numbers_that_sum_zero = []
total = 0
for i in range(len(my_list)):
total += my_list[i]
numbers_that_sum_zero.append(my_list[i])
if total == 0:
break
print(numbers_that_sum_zero)
This will return
[-1, 5, 6, -7, -3]
An option using numpy:
import numpy as np
my_list = [-1, 5, 6, -7, -3, 7, 9, -8, 4, -12]
a = np.array(my_list)
result = a[:a.cumsum().tolist().index(0)+1]
# or result = a[:np.where(a.cumsum()==0)[0][0]+1]
Output:
array([-1, 5, 6, -7, -3])
This returns the first subset of number in which the sum is 0. If there's no values in the list that sums to 0 at all, it raises an error.
You can handle it to return NaN or any other output with:
try:
result = a[:a.cumsum().tolist().index(0)+1]
except:
result = np.nan

Building a list of random multiplication examples

I have two 100-element lists filled with random numbers between 1 and 10.
I want to make a list of multiplications of randomly selected numbers that proceeds until a product greater than 50 is generated.
How can I obtain such a list where each element is a product and its two factors?
Here is the code I tried. I think it has a lot of problems.
import random
list1 = []
for i in range(0,1000):
x = random.randint(1,10)
list1.append(x)
list2 = []
for i in range(0,1000):
y = random.randint(1,10)
list2.append(y)
m=random.sample(list1,1)
n=random.sample(list2,1)
list3=[]
while list3[-1][-1]<50:
c=[m*n]
list3.append(m)
list3.append(n)
list3.append(c)
print(list3)
The output I want
[[5.12154, 4.94359, 25.3188], [1.96322, 3.46708, 6.80663], [9.40574,
2.28941, 21.5336], [4.61705, 9.40964, 43.4448], [9.84915, 3.0071, 29.6174], [8.44413, 9.50134, 80.2305]]
To be more descriptive:
[[randomfactor, randomfactor, product],......,[[randomfactor,
randomfactor, greater than 50]]
Prepping two lists with 1000 numbers each with numbers from 1 to 10 in them is wasted memory. If that is just a simplification and you want to draw from lists you got otherwise, simply replace
a,b = random.choices(range(1,11),k=2)
by
a,b = random.choice(list1), random.choice(list2)
import random
result = []
while True:
a,b = random.choices(range(1,11),k=2) # replace this one as described above
c = a*b
result.append( [a,b,c] )
if c > 50:
break
print(result)
Output:
[[9, 3, 27], [3, 5, 15], [8, 5, 40], [5, 9, 45], [9, 3, 27], [8, 5, 40], [8, 8, 64]]
If you need 1000 random ints between 1 and 10, do:
random_nums = random.choices(range(1,11),k=1000)
this if much faster then looping and appending single integers 1000 times.
Doku:
random.choices(iterable, k=num_to_draw)
random.choice(iterable)

How-to Create A List From An Existant List

I'm having some issues with an exercise assignment on python:
I need to take a list of items, lets say lst = [1, 4, 37, 48, 7, 15], and create a function that would allow me to extract from this list all numbers that are divisible by one and/or by themselves, creating a new list of items.
lst = [1, 4, 37, 48, 7, 15], z is non negative.
def func(lst,z):
y = []
z > 0
for i in lst:
if (i % z == 0):
y.append(i)
return y
print(func(lst,z))
Output: [1, 4, 37, 48, 7, 15]
I get the same result list/result.
Well, isn't every number divisible by itself and 1? That is why your list is the same.
Setting z=4 yields [4,48], which is every number that is divisible by 1, itself, and 4.

theano finding the indices of a tensor elements in a second tensor

I can't seem to find a solution for this. Given two theano tensors a and b, I want to find the indices of elements in b within the tensor a. This example will help, say a = [1, 5, 10, 17, 23, 39] and b = [1, 10, 39], I want the result to be the indices of the b values in tensor a, i.e. [0, 2, 5].
After spending some time, I thought the best way would be to use scan; here is my shot at the minimal example.
def getIndices(b_i, b_v, ar):
pI_subtensor = pI[b_i]
return T.set_subtensor(pI_subtensor, np.where(ar == b_v)[0])
ar = T.ivector()
b = T.ivector()
pI = T.zeros_like(b)
result, updates = theano.scan(fn=getIndices,
outputs_info=None,
sequences=[T.arange(b.shape[0], dtype='int32'), b],
non_sequences=ar)
get_proposal_indices = theano.function([b, ar], outputs=result)
d = get_proposal_indices( np.asarray([1, 10, 39], dtype=np.int32), np.asarray([1, 5, 10, 17, 23, 39], dtype=np.int32) )
I am getting the error:
TypeError: Trying to increment a 0-dimensional subtensor with a 1-dimensional value.
in the return statement line. Further, the output needs to be a single tensor of shape b and I am not sure if this would get the desired result. Any suggestion would be helpful.
It all depends on how big your arrays will be. As long as it fits in memory you can proceed as follows
import numpy as np
import theano
import theano.tensor as T
aa = T.ivector()
bb = T.ivector()
equality = T.eq(aa, bb[:, np.newaxis])
indices = equality.nonzero()[1]
f = theano.function([aa, bb], indices)
a = np.array([1, 5, 10, 17, 23, 39], dtype=np.int32)
b = np.array([1, 10, 39], dtype=np.int32)
f(a, b)
# outputs [0, 2, 5]

Resources