How I can optimize the given below my python code? - python

I have an array and given an array of size N containing positive integers and I want to count number of smaller elements on right side of each array.
for example:-
Input:
N = 7
arr[] = {12, 1, 2, 3, 0, 11, 4}
Output: 6 1 1 1 0 1 0
Explanation: There are 6 elements right
after 12. There are 1 element right after
1. And so on.
And my code for this problem is like as :-
# python code here
n=int(input())
arr=list(map(int,input().split()))
ans=0
ANS=[]
for i in range(n-1):
for j in range(i+1,n):
if arr[i]>arr[j]:
ans+=1
ANS.append(ans)
ans=0
ANS.append(0)
print(ANS)
but the above my code take O(n^2) time complexity and I want to reduce the this. If anyone have any idea to reduce above python code time complexity please help me. Thank you.

This solution is O(n log(n)) as it is three iterations over the values and one sorting.
arr = [12, 1, 2, 3, 0, 11, 4]
# Gather original index and values
tups = []
for origin_index, el in enumerate(arr):
tups.append([origin_index, el])
# sort on value
tups.sort(key=lambda t: t[1])
res = []
for sorted_index, values in enumerate(tups):
# check the difference between the sorted and original index
# If there is a positive value we have the n difference smaller
# values to the right of this index value.
if sorted_index - values[0] > 0:
res.append([values[0], (sorted_index - values[0])])
elif sorted_index - values[0] == 0:
res.append([values[0], (sorted_index - values[0]) + 1])
else:
res.append([values[0], 0])
origin_sort_res = [0 for i in range(len(arr))]
for v in res:
# Return the from the sorted array to the original indexing
origin_sort_res[v[0]] = v[1]
print(origin_sort_res)

try this(nlog2n)
def solution(nums):
sortns = []
res = []
for n in reversed(nums):
idx = bisect.bisect_left(sortns, n)
res.append(idx)
sortns.insert(idx,n)
return res[::-1]
print(solution([12, 1, 2, 3, 0, 11, 4]))
# [6, 1, 1, 1, 0, 1, 0]

Related

remove zeros between values of a list

I have a list of list and I want to remove zero values that are between numbers in each list. All my lists inside my list have same lenght.
For example:
List1=[[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
desired output:
list2=[[0,1,2,3,0,0],[0,5,6,9,0]]
I was thinking about using indices to identify the first non zero value and last non zero value, but then I don't know how I can remove zeros between them.
You have the right idea, I think, with finding the first and last indices of nonzeroes and removing zeroes between them. Here's a function that does that:
def remove_enclosed_zeroes(lst):
try:
first_nonzero = next(
i
for (i, e) in enumerate(lst)
if e != 0
)
last_nonzero = next(
len(lst) - i - 1
for (i, e) in enumerate(reversed(lst))
if e != 0
)
except StopIteration:
return lst[:]
return lst[:first_nonzero] + \
[e for e in lst[first_nonzero:last_nonzero] if e != 0] + \
lst[last_nonzero:]
list1 = [[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
list2 = [remove_enclosed_zeroes(sublist) for sublist in list1]
# [[0, 1, 2, 3, 0, 0], [0, 5, 6, 9, 0]]
Inspired by #python_user I thought about this a bit more and came up with this simpler solution:
def remove_internal_zeros(lst):
return [v for i, v in enumerate(lst) if v or not any(lst[i+1:]) or not any(lst[:i])]
This works by passing any value from the original list which is either
not zero (v); or
zero and not preceded by a non-zero value (not any(lst[:i])); or
zero and not followed by a non-zero value (not any(lst[i+1:]))
It can also be written as a list comprehension:
list2 = [[v for i, v in enumerate(lst) if v or not any(lst[:i]) or not any(lst[i+1:])] for lst in list1]
Original Answer
Here's another brute force approach, this pops all the zeros off either end of the list into start and end lists, then filters the balance of the list for non-zero values:
def remove_internal_zeros(l):
start_zeros = []
# get starting zeros
v = l.pop(0)
while v == 0 and len(l) > 0:
start_zeros.append(0)
v = l.pop(0)
if len(l) == 0:
return start_zeros + [v]
l = [v] + l
# get ending zeros
end_zeros = []
v = l.pop()
while v == 0 and len(l) > 0:
end_zeros.append(0)
v = l.pop()
# filter balance of list
if len(l) == 0:
return start_zeros + [v] + end_zeros
return start_zeros + list(filter(bool, l)) + [v] + end_zeros
print(remove_internal_zeros([0,1,0,2,3,0,0]))
print(remove_internal_zeros([0,5,6,0,0,9,0]))
print(remove_internal_zeros([0,0]))
print(remove_internal_zeros([0,5,0]))
Output:
[0, 1, 2, 3, 0, 0]
[0, 5, 6, 9, 0]
[0, 0]
[0, 5, 0]
I think this has to be done with brute force.
new = []
for sub in List1:
# Find last non-zero.
for j in range(len(sub)):
if sub[-1-j]:
lastnonzero = len(sub)-j
break
print(j)
newsub = []
firstnonzero = False
for i,j in enumerate(sub):
if j:
firstnonzero = True
newsub.append(j)
elif i >= lastnonzero or not firstnonzero:
newsub.append(j)
new.append(newsub)
print(new)
Please try this, remove all 0 between numbers in each list.:
list1=[[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
rowIndex=len(list1) # count of rows
colIndex=len(list1[0]) # count of columns
for i in range(0, rowIndex):
noZeroFirstIndex = 1
noZeroLastIndex = colIndex - 2
for j in range(1, colIndex - 1):
if(list1[i][j] != 0):
noZeroFirstIndex = j
break
for j in range(colIndex -2, 0, -1):
if(list1[i][j] != 0):
noZeroLastIndex = j
break
for j in range(noZeroLastIndex, noZeroFirstIndex, -1):
if(list1[i][j] == 0 ):
del list1[i][j]
print(list1)
Result:
[[0, 1, 2, 3, 0, 0], [0, 5, 6, 9, 0]]
I wrote a pretty straight-forward approach. Try this.
def removeInnerZeroes(list):
listHold=[]
listNew = []
firstNonZeroFound = False
for item in list:
if item==0:
if firstNonZeroFound:
listHold.append(item)
else:
listNew.append(item)
else:
firstNonZeroFound=True
listHold.clear()
listNew.append(item)
listNew.extend(listHold)
return listNew
complexList = [[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
print(complexList)
complexListNew = []
for listi in complexList:
complexListNew.append(removeInnerZeroes(listi))
print(complexListNew)
One way to do it is to treat each sublist as 3 sections:
Zeros at the front, if any
Zeros at the end, if any
Numbers in the middle from which zeros are to be purged
itertools.takewhile is handy for the front and end bits.
from itertools import takewhile
List1=[[0,1,0,2,3,0,0],[0,5,6,0,0,9,0]]
def purge_middle_zeros(numbers):
is_zero = lambda x: x==0
leading_zeros = list(takewhile(is_zero, numbers))
n_lead = len(leading_zeros)
trailing_zeros = list(takewhile(is_zero, reversed(numbers[n_lead:])))
n_trail = len(trailing_zeros)
mid_numbers = numbers[n_lead:-n_trail] if n_trail else numbers[n_lead:]
mid_non_zeros = [x for x in mid_numbers if x]
return leading_zeros + mid_non_zeros + trailing_zeros
list2 = [purge_middle_zeros(sub_list) for sub_list in List1]
list2
[[0, 1, 2, 3, 0, 0], [0, 5, 6, 9, 0]]
Other notes:
the lambda function is_zero tells takewhile what the criteria are for continuing, in this case "keep taking while it's a zero"
for the mid_non_zeros section the list comprehension [x for.... ] takes all the numbers except for the zeros (the if x at the end applies the filter)
slicing notation to pick out the middle of the list, numbers[from_start:-from_end] with the negative -from_end meaning 'except for this many elements at the end'. The case where there are no trailing zeros requires a different slice expression, i.e. numbers[from_start:]
I wrote the following code out of curiosity, that is somewhat intuitive and mimics a "looking item-by-item" approach.
def remove_zeros_inbetween(list_):
new_list = list_.copy()
for j, l in enumerate(list_): # loop through the inner lists
checking = False
start = end = None
i = 0
deleted = 0
while i < len(l): # loop through the values of an inner list
if l[i] == 0: # ignore
i += 1
continue
if l[i] != 0 and not checking: # non-zero value found
checking = True # start checking for zeros
start = i
elif l[i] != 0 and checking: # if got here and checking, the finish checking
checking = False
end = i
if start and end: # if both values have been set, i.e, different to None
# delete values in-between
new_list[j] = new_list[j][:(start+1-deleted)] + new_list[j][(end-deleted):]
deleted += end - start - 1
if l[i] != 0: # for the case of two non-zero values
start = i
checking = True
else:
i = end # ignore everything up to end
end = None # restart check
i += 1
return new_list
>>> remove_zeros_inbetween([[0, 1, 0, 2, 3, 0, 5], [0, 5, 6, 0, 0, 9, 4]])
[[0, 1, 2, 3, 5], [0, 5, 6, 9, 4]]
>>> remove_zeros_inbetween([[0, 0], [0, 3, 0], [0]]))
[[0, 0], [0, 3, 0], [0]]
>>> remove_zeros_inbetween([[0, 0, 0, 0]]))
[[0, 0, 0, 0]]
You start by replacing 0 by "0" - which is not necessary. Secondly your filter call does not save the resulting list; try:
list1[i] = list(filter(lambda a: a !=0, list1[1:-1])) # changed indexing , I suppose this could work

how do I reference first argument of an enumeration?

I am writing code with enumerate() in Python, and I am having issues with referencing the first argument in enumerate:
For example, let nums be temperatures of different days:
nums = [1,5,20,9,3,10,50,7]
array = []
for j, distance in enumerate(nums):
for k, distance2 in enumerate(nums[1:],1):
if nums[j] < nums[k]:
array.append(distance2[j]-distance[k])
So, the challenge I have is: how do I reference the 'distance' and 'distance2' of each element respectively in my enumerations?
The aim of the problem is to determine for each day, how many days you'll have to wait for a warmer day, so for the example above, the output would be [1,1,4,3,1,1,0,0]; where there are no warmer days ahead, return 0.
Thanks
You need to calculate the distance based off the indexes not the values at the index.
You should not restart your subscript and inner index at 1 each time but rather at i each iteration.
nums = [1, 5, 20, 9, 3, 10, 50, 7]
array = []
for i, curr_temp in enumerate(nums):
days = 0
for j, future_temp in enumerate(nums[i:], i):
if curr_temp < future_temp:
# Set Days to Distance between Indexes
days = j - i
# Stop Looking Once Higher Value Found
break
array.append(days)
print(array)
Output:
[1, 1, 4, 2, 1, 1, 0, 0]

Given an Int Array, Find Two Integers with the Smallest Difference that has the Sum M

Given an unordered integer list, print two integers that total to m in this manner int1 int2 (int 1 is less than or equal to int 2, and they are separated by a space). Assume that there is always a solution for m in the integer list. int1 and int2 must be positive integers.
If there are multiple solutions, print the integer pair with the least difference.
Example:
Li = [2, 6, 8, 10, 4]
m = 10
Output:
4 6
Here's my code but according to our compiler (this is an exercise in our class), I have wrong outputs for the hidden test cases.
li = [2, 6, 8, 10, 4]
m = int(input())
selection = {} # I created a dictionary to put all pairs, sort them
# and print the pair with the least difference.
for j in li:
index = li.index(j)
temp = li.pop(index)
if m-j in li and j != m: # checks if m-j is present in the list, and j
# does not equal to m, since we're only looking
# for positive integer pairs
if abs(j - (m-j)) not in selection : # don't have to rewrite in the dict
# if pair is already written.
selection[abs(j - (m-j))] = [min(j, m-j), max(j, m-j)]
li.insert(index, temp)
output = min(selection.keys()) # gets the pair with the minimum difference in the dict
print(*selection[output])
UPDATE: Code works!
Code:
Li = [2, 6, 8, 10, 4]
m = 10
#Output:
#4 6
m_satisfied = []
for i in range(len(Li) - 1):
for j in range(i+1, len(Li)):
if (Li[i] + Li[j]) == m:
m_satisfied.append(tuple([Li[i], Li[j]]))
diff_dict = {i: abs(t[0] - t[1]) for i,t in enumerate(m_satisfied)}
least_diff = min(diff_dict.values())
ind_m_satisfied = [k for k, v in diff_dict.items() if v == least_diff]
res_int = [m_satisfied[i] for i in ind_m_satisfied]
print(res_int)
print(res_int[0][0], res_int[0][1])
Output:
[(6, 4)]
6 4

Using abs() in a list in Python

I am trying to create a list of integers and then scan it in order to find the minimum absolute value of the substractions of the elements of the list. I have created the list, but there is problem in the code which finds the minimum absolute value, as the result it shows is not correct. I think it is probably in the possitions of the elements of the list during the loops. Can you help me find it?
For example, when I create a list Α = [2, 7, 5, 9, 3, 1, 2], the result of min should be 0, but it is 1.
Here is my code:
min=1000
for i in range (1, N-1):
for j in range (i+1, N):
if (abs (A [i-1] - A [j-1])<min):
min = abs (A [i-1] - A [j-1])
print ("%d" %min)
You can do it like this:
A = [2, 7, 5, 9, 3, 1, 2]
temp = sorted(A)
min_diff = min([abs(i - j) for i, j in zip(temp [:-1], temp [1:])])
print(min_diff) # -> 0
Sorting makes sure that the element pair (i, j) which produce the overall smallest difference would be a pair of consecutive elements. That makes the
number of checks you have to perform much less than the brute force approach of all possible combinations.
Something a bit more clever that short-circuits:
A = [2, 7, 5, 9, 3, 1, 2]
def find_min_diff(my_list):
if len(set(my_list)) != len(my_list): # See note 1
return 0
else:
temp = sorted(my_list)
my_min = float('inf')
for i, j in zip(temp [:-1], temp [1:]):
diff = abs(i - j)
if diff < my_min:
my_min = diff
return my_min
print(find_min_diff(A)) # -> 0
Notes:
1: Converting to set removes the duplicates so if the corresponding set has less elements than the original list it means that there is at least one duplicate value. But that necessarily means that the min absolute difference is 0 and we do not have to look any further.
I would be willing to bet that this is the fastest approach for all lists that would return 0.
You should not be subtracting 1 from j in the inner loop as you end up skipping the comparison of the last 2. It is better to make the adjustments in the loop ranges, rather than subtracting 1 (or not) in the loop code:
A = [2, 7, 5, 9, 3, 1, 2]
N = 7
mint = 1000
for i in range (0, N-1):
for j in range (i+1, N):
if (abs(A[i] - A[j]) < mint):
mint = abs(A[i] - A[j])
print(i, j)
print(mint)
print(mint) # 0
I have also avoided the use of a built-in function name min.
To avoid the arbitrary, magic, number 1000, you can perform an initial check against None:
A = [2, 7, 5, 9, 3, 1, 2]
N = 7
mint = None
for i in range (0, N-1):
for j in range (i+1, N):
if mint is None:
mint = abs(A[i] - A[j])
elif (abs(A[i] - A[j]) < mint):
mint = abs(A[i] - A[j])
print(i, j)
print(mint)
print(mint) # 0
This is a brute-force solution:
from itertools import combinations
A = [2, 7, 5, 9, 3, 1, 2]
min(abs(i-j) for i, j in combinations(A, 2)) # 0
using numpy
import numpy as np
A = [2, 7, 5, 9, 3, 1, 2]
v = np.abs(np.diff(np.sort(np.array(A))))
np.min(v)
out : 0
Or You can use numpy only for the diff part like this :
v = min(abs(np.diff(sorted(A))))
This is what you are looking for:
A = [2, 7, 5, 9, 3, 1, 2]
diffs = []
for index1, i in enumerate(A):
for index2, j in enumerate(A):
if index1 != index2:
diffs.append(abs(i-j))
print(min(diffs))
Output:
0
Updated to exclude subtraction of same items

Check if values in list exceed threshold a certain amount of times and return index of first exceedance

I am searching for a clean and pythonic way of checking if the contents of a list are greater than a given number (first threshold) for a certain number of times (second threshold). If both statements are true, I want to return the index of the first value which exceeds the given threshold.
Example:
# Set first and second threshold
thr1 = 4
thr2 = 5
# Example 1: Both thresholds exceeded, looking for index (3)
list1 = [1, 1, 1, 5, 1, 6, 7, 3, 6, 8]
# Example 2: Only threshold 1 is exceeded, no index return needed
list2 = [1, 1, 6, 1, 1, 1, 2, 1, 1, 1]
I don't know if it's considered pythonic to abuse the fact that booleans are ints but I like doing like this
def check(l, thr1, thr2):
c = [n > thr1 for n in l]
if sum(c) >= thr2:
return c.index(1)
Try this:
def check_list(testlist)
overages = [x for x in testlist if x > thr1]
if len(overages) >= thr2:
return testlist.index(overages[0])
# This return is not needed. Removing it will not change
# the outcome of the function.
return None
This uses the fact that you can use if statements in list comprehensions to ignore non-important values.
As mentioned by Chris_Rands in the comments, the return None is unnecessary. Removing it will not change the result of the function.
If you are looking for a one-liner (or almost)
a = filter(lambda z: z is not None, map(lambda (i, elem) : i if elem>=thr1 else None, enumerate(list1)))
print a[0] if len(a) >= thr2 else false
A naive and straightforward approach would be to iterate over the list counting the number of items greater than the first threshold and returning the index of the first match if the count exceeds the second threshold:
def answer(l, thr1, thr2):
count = 0
first_index = None
for index, item in enumerate(l):
if item > thr1:
count += 1
if not first_index:
first_index = index
if count >= thr2: # TODO: check if ">" is required instead
return first_index
thr1 = 4
thr2 = 5
list1 = [1, 1, 1, 5, 1, 6, 7, 3, 6, 8]
list2 = [1, 1, 6, 1, 1, 1, 2, 1, 1, 1]
print(answer(list1, thr1, thr2)) # prints 3
print(answer(list2, thr1, thr2)) # prints None
This is probably not quite pythonic though, but this solution has couple of advantages - we keep the index of the first match only and have an early exit out of the loop if we hit the second threshold.
In other words, we have O(k) in the best case and O(n) in the worst case, where k is the number of items before reaching the second threshold; n is the total number of items in the input list.
I don't know if I'd call it clean or pythonic, but this should work
def get_index(list1, thr1, thr2):
cnt = 0
first_element = 0
for i in list1:
if i > thr1:
cnt += 1
if first_element == 0:
first_element = i
if cnt > thr2:
return list1.index(first_element)
else:
return "criteria not met"
thr1 = 4
thr2 = 5
list1 = [1, 1, 1, 5, 1, 6, 7, 3, 6, 8]
list2 = [1, 1, 6, 1, 1, 1, 2, 1, 1, 1]
def func(lst)
res = [ i for i,j in enumerate(lst) if j > thr1]
return len(res)>=thr2 and res[0]
Output:
func(list1)
3
func(list2)
false

Categories