Related
I have a large data of 145000 items (a bill of materials) and I want to check the % of shared items between two bill of materials.
Two for loops or other methods always run in similar time periods.
What is the fastest way to do this?
First&secondbill are the lists with components in them:
for FKid in FirstBill:
for SKid in SecondBill:
CommonChild = (CommonChild + 1) if FKid == SKid else CommonChild
return CommonChilds / len(FirstBill)
Kinda optimal to use one set
# Python program to illustrate the intersection
# of two lists in most simple way
def intersection(lst1, lst2):
temp = set(lst2)
lst3 = [value for value in lst1 if value in temp ]
return lst3
# Driver Code
lst1 = [4, 9, 1, 17, 11, 26, 28, 54, 69]
lst2 = [9, 9, 74, 21, 45, 11, 63, 28, 26]
#print(intersection(lst1, lst2))
quantity = len(intersection(lst1, lst2))
Assuming that ids in the bills are unique, a simpler answer would be:
percentage = sum([1 for fkid in FirstBill if fkid in SecondBill]) / len(FirstBill) * 100
or
percentage = len(set(FirstBill).intersection(set(SecondBill))) / len(FirstBill) * 100
I'll do my best to explain my concern.
This problem is a practice activity for me as I learn python.
How could I check one by one if the element of the first lists is bigger than the element on the second lists then subtract?
Example:
# inputted values
list1 = [50,40,90,30]
list2 = [40,50,40,20]
# desired output:
output = [10,40,50,10]
You needs some real lists, not just four variables. Then do this.
list1=[50,40, 90, 30]
list2=[40, 50, 40, 20]
output=[p1-p2 if p1>p2 else p1 for (p1, p2) in zip(list1, list2)]
print(output) #==> [10, 40, 50, 10]
You essentially need to iterate over both lists together and compare each element pairwise, then the output will be element from list1 if it is smaller than the element in list2, or else the output will be the difference of list2's element and list1's element
Two ways to achieve this
List-comprehension by simultaneously iterating on both lists
list1 = [50,40,90,30]
list2 = [40,50,40,20]
print([list1[idx] if list1[idx] < list2[idx] else list1[idx] - list2[idx] for idx in range(len(list1))])
Output is [10, 40, 50, 10]
List-comprehension by iterating on the iterator created by zipping both lists together
list1 = [50,40,90,30]
list2 = [40,50,40,20]
print([item1 if item1 < item2 else item1 - item2 for item1, item2 in zip(list1, list2)])
Output is [10, 40, 50, 10]
I don't understand why we are all answering a new python dev with list comps, I believe that a newly minted dev should first start with an easier syntax, and let them learn about the python features (like list comps) that can improve their code.</rant>
To answer your question,
1. you can iterate multiple lists of the same length using python's built-in zip which takes multiple iterables as arguments and returns a tuple with the current element of each iterator at the same index, the function works like this;
list1 = [50,40,90,30]
list2 = [40,50,40,20]
for i1, i2 in zip(list1, list2):
print(i1, i2)
# result
50, 40
40, 50
90, 40
30, 20
and then 2. you can start adding your logic at each iteration;
# if you want to store the results use the results list.
results = []
list1 = [50,40,90,30]
list2 = [40,50,40,20]
for i1, i2 in zip(list1, list2):
if i1 > i2:
result.append(i1 - i2)
# or if you don't need to store the results, just use...
print(i1 - i2)
else:
result.append(i1)
# same here...
print(i1)
# result
10
40
50
10
# results == [10, 40, 50, 10]
It might be an overkill to use numpy but the syntax is clear and concise:
>>> import numpy as np
>>> a1 = np.array([50, 40, 90, 30])
>>> a2 = np.array([40, 50, 40, 20])
>>> np.where(a1 >= a2, a1 - a2, a1)
array([10, 40, 50, 10])
How can I write a function which takes a list of integers and creates a new list with the same number of elements as the original list such that each integer in the new list is the sum of its neighbours and itself in the original list. For example, if a_list = [10, 20, 30, 40, 50], the new_list = [30, 60, 90, 120, 90].
I tried a list comprehension;
def sum_neighbours(a_list):
b_list = a_list
li = [x+y for x in a_list for y in b_list]
return li
print(sum_neighbours([10, 20, 30, 40, 50]))
Which gave me;
[20, 30, 40, 50, 60, 30, 40, 50, 60, 70, 40, 50,
60, 70, 80, 50, 60, 70, 80, 90, 60, 70, 80, 90, 100]
I then tried a for loop;
def sum_neighbours(a_list):
element1 = a_list[0]
new_list = []
for element in a_list:
element1 += element
new_list += element1
return new_list
print(sum_neighbours([10,20,30,40,50]))
Which threw a TypeError: 'int' object is not iterable
But in both cases I don't think my ideas/attempts are on the right track... I would really appreciate any help, hints, tips that more experienced people may have.
You can start with a solution that iterates through the indexes of the list, like so:
def sum_neighbours1(a_list):
result = []
for i in range(len(a_list)):
if i == 0:
result.append(a_list[i] + a_list[i+1])
elif i == len(a_list)-1:
result.append(a_list[i-1] + a_list[i])
else:
result.append(a_list[i-1] + a_list[i] + a_list[i+1])
return result
print(sum_neighbours1([10,20,30,40,50]))
Or, you can build three distinct lists: the original list, the list of left-hand neighbors, and the list of right-hand neighbors. We have to put 0 at the front or rear of the auxiliary lists. Each of the lists must be at least as long as the original list.
Zip the three lists together, and add them:
def sum_neighbours2(a_list):
priors = [0] + a_list
subsequents = a_list[1:] + [0]
return map(sum, zip(priors, a_list, subsequents))
Note that I used the functional notation map(sum, data), but I could have used a list conprehension just as easily:
def sum_neighbours3(a_list):
priors = [0] + a_list
subsequents = a_list[1:] + [0]
return [p+a+s for p,a,s in zip(priors, a_list, subsequents)]
And, if I were eager to make the result a single expression (for example, if it had to fit in a lambda expression), here that is:
def sum_neighbours4(a_list):
return [
left + a + right
for left, a, right in zip(
[0] + a_list,
a_list,
a_list[1:] + [0])
]
Here is my one line solution with zip :
def sum_neighbours(a) :
return [sum(x) for x in [(a[0],a[1])]+zip(a,a[1:],a[2:])+[(a[-2],a[-1])]]
print sum_neighbours([10, 20, 30, 40, 50]) # display [30, 60, 90, 120, 90]
with :
a, the original list
zip(a,a[1:],a[2:]), 3-tuples generation
[(a[0],a[1])] and [(a[-2],a[-1])], 2-tuples for particular cases (first and last numbers of list)
You'll probably want a for i in range loop, and indexing directly into the array so you can look at the element that is at i+1 and i-1 indexes (making sure to check that your +/- 1 isn't going outside the bounds of the array).
I've achived these two things.
Find all possible sublists of a list in given range (i ,j).
A = [ 44, 55, 66, 77, 88, 99, 11, 22, 33 ]
Let, i = 2 and j = 4
Then, Possible sublists of the list "A" in the given range (2,4) is :
[66], [66,77], [66,77,88], [77], [77,88], [88]
And, minimum of the resultant product after multipying all the elements of the sublists:
So, the resultant list after multiplying all the elements in the above sublists will become
X = [66, 5082, 447216, 77, 6776, 88]`
Now, the minimum of the above list, which is min(X) i.e 66
My Code:
i, j = 2, 4
A = [ 44, 55, 66, 77, 88, 99, 11, 22, 33 ]
O, P = i, i
mini = A[O]
while O <= j and P <= j:
if O == P:
mini = min(mini, reduce(lambda x, y: x * y, [A[O]]))
else:
mini = min(mini, reduce(lambda x, y: x * y, A[O:P + 1]))
P += 1
if P > j:
O += 1
P = O
print(mini)
My Question:
This code is taking more time to get executed for the Larger Lists and Larger Ranges ! Is there any possible "Pythonic" way of reducing the time complexity of the above code ? Thanks in advance !
EDIT :
Got it. But, If there is more than one such possible sublist with the same minimum product,
I need the longest sub list range (i,j)
If there are still more than one sublists with the same "longest sub range", I need to print the sub-interval which has the lowest start index.
Consider this list A = [2, 22, 10, 12, 2] if (i,j) = (0,4).
There is a tie. Min product = 2 with two possibilities '(0,0)' and '(4,4)' . Both sub list range = 0 [ (0-0) and (4-4) ]
In this case i need to print (minproduct, [sublist-range]) = 2, [0,0]
Tried using dictionaries, It works for some inputs but not for all ! How to do this 'efficiently' ?
Thank you !
First, given the list and the index range, we can get the sublist A[i : j + 1]
[66, 77, 88]
For positive integers a and b, a * b is no less than a or b. So you don't need to do multiplying, it's not possible that multiplying of two or more elements has a smaller result. The minimum of this list is the minimum of all the multiplying results.
So the result is:
min(A[i : j + 1])
For generating the sublists, it is as simple as two nested for loops in a list comprehension:
def sublists(l,i,j):
return [l[m:n+1] for m in range(i,j+1) for n in range(m,j+1)]
example:
>>> sublists(A,2,4)
[[66], [66, 77], [66, 77, 88], [77], [77, 88], [88]]
For finding the minimum product:
>>> min(map(prod, sublists(A,2,4)))
66
(you import prod from numpy, or define it as def prod(x): return reduce(lambda i,j:i*j,x))
The accepted answer is correct for all positive ints as you cannot multiply the smallest element by any number and get a smaller result. It might make more sense if you were getting all the slices greater than length 1.
If you were going to calculate it then you could use itertools.islice to get each slice and get the min using a generator expression:
from itertools import islice
from operator import mul
print(min(reduce(mul, islice(A, n, k + 1), 1)
for n in range(i, j + 1) for k in range(n, j + 1)))
66
If for i = 0 and j = 4 you considered (44, 55, 66, 88) a legitimate slice then you would need to use itertools.combinations.
#EDIT: Quick Solution:
min(A[i:j+1])
Since all the numbers are positive integers, and you want to find the minimum product of all possible sublists of A[i:j+1] list
slice, it will also contain sublists of length 1. The minimum products of all such sublists will be lowest number among the A[i:j+1] slice.
Another Solution:
The below method will be useful when you need to find the maximum product of sublists or you need all the possible combinations of A[i:j+1] list slice.
We'll use itertools.combinations to solve this. We can do this in 3 steps.
Step1: Get the slice of the list
my_list = A[i:j+1]
This will give us the slice to work on.
my_list = A[2:5]
my_list
[66, 77, 88]
Step-2 Generate all possible combinations:
import itertools
my_combinations = []
for x in range(1, len(my_list)+1):
my_combinations.extend(list(itertools.combinations(my_list,x)))
my_combinations
[(66,), (77,), (88,), (66, 77), (66, 88), (77, 88), (66, 77, 88)]
iterools.combinations returns r length subsequences of elements from
the input iterable
So, we will use this to generate subsequences of length 1 to length equal to length of my_list. We will get a list of tuples with each element being a subsequence.
Step-3 : Find min product of all possible combinations
products_list = [reduce(lambda i,j:i*j, x) for x in my_combinations]
[66, 77, 88, 5082, 5808, 6776, 447216]
min(products_list)
66
After getting the subsequences, we apply list comprehension along with reduce() to get the list of products for all the subsequences in my_combinations list. Then we apply min() function to get the minimum product out of the products_list which will give us our answer.
Take a look a itertools.combinations()
https://docs.python.org/3/library/itertools.html#itertools.combinations
Call it passing the sublist, in a loop, with the other parameter varying from 1 to the length of the sublist.
It will definitely take "more time to get executed for the Larger Lists and Larger Ranges", i think that's inevitable. But might be much faster than your approach. Measure and see.
def solution(a_list):
sub = [[]]
for i in range(len(a_list)):
for j in range(len(a_list)):
if(i == j):
sub.append([a_list[i]])
elif(i > j):
sub.append([a_list[j],a_list[i]])
sub.append(a_list)
return sub
solution([10, 20, 30])
[[], [10], [10, 20], [20], [10, 30], [20, 30], [30], [10, 20, 30]]
Hey guys trying to finish my program. Here is my code:
lists = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
#I want to make a new list consisting of only numbers above 50 from that list
if any(list > 50 for list in list):
newlists = list
I don't know how to do it. I'm doing something wrong, can anyone help me?
something like this will work:
new_list = [ x for x in lists if x > 50 ]
This is known as a "list comprehension" and can be extremely handy.
newlist = [x for x in lists if x > 50]
Read about list comprehensions here
Two options. Using list comprehensions:
lst = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
[x for x in lst if x > 50]
And using filter in Python 2.x:
filter(lambda x: x > 50, lst)
Or using filter in Python 3.x, as pointed in the comments, filter returns an iterator in this version and if needed, the result needs to be converted to a list first:
list(filter(lambda x: x > 50, lst))
Anyway, the result is as expected:
=> [60, 70, 80, 90, 100]