finding minimal difference - python

I have an array A=[a1,a2,a3,a4,a5...] and I want to find two elements of the array, say A[i] and A[j] such that i is less than j and A[j]-A[i] is minimal.
Would this code do the job:
def findMinDifference(A):
Unsorted=[]
minDiff=1000000
Unsorted=A
Sorted=quickSort(A)
for i in range(0,len(Sorted)):
if i>=1:
SmallElement=Sorted[i-1]
indexOfSmaller=Unsorted.index(SmallElement)
BigElement=Sorted[i]
indexOfBig=Unsorted.index(BigElement)
if indexOfSmaller<inexOfBig:
diff=Sorted[i]-Sorted[i-1]
if diff<minDiff:
minDiff=diff
return minDiff

Your code can be updated a bit:
a = [1,2,5,9,10,20,21,45]
a, size = sorted(a), len(a)
res = [a[i + 1] - a[i] for i in xrange(size) if i+1 < size]
print "MinDiff: {0}, MaxDiff: {1}.".format(min(res), max(res))
In two words - finding min or max diff can be simplified as getting min/max element of a list that consist of differences for each pair of elements from the sorted original list of values

Using itertools pairwise recipe:
>>> from itertools import tee, izip
>>> def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
>>> nums = [1, 3, 7, 13, 9, 18, 22]
>>> min(pairwise(sorted(nums)), key=lambda x: x[1] - x[0])
(1, 3)

Not sure why the sort. You can adapt this pseudocode.
for i = 0; i < array.length; i++
for j = i + 1; j < array.length; j++
if a[j] - a[i] < min
min = a[j] - a[i]
return min

This is another approach, using more iterables and more relying on defaults:
from itertools import imap, islice, izip
def find_min_diff(iterable, sort_func=sorted):
sorted_iterable = sort_func(iterable)
return min(imap(
lambda a, b: b - a,
izip(sorted_iterable, islice(sorted_iterable, 1)),
))

Related

Comparing elements in two lists in python

I have a function that compares the elements of two lists and returns the difference between them. I have two versions of it. The first one works but not the second one. What is wrong with the second function? The inputs a and b are two lists of same length.
def compareLists(a, b):
A = sum([1 if i > j else 0 for i, j in zip(a, b)])
B = sum([1 if j > i else 0 for i, j in zip(a, b)])
return (A, B)
def compareLists(a, b):
A = sum([1 for i in range(0, len(a)) if a[i] > b[i] else 0])
B = sum([1 for i in range(0, len(a)) if b[i] > a[i] else 0])
return (A, B)
Eg input and output: a = [1, 2, 3,4]; b = [0, -2, 5, 6]; output = (2, 2)
You don't need the ternary operator (if-else) in the second code since using the if expression in a list comprehension is how the output can be filtered:
A = sum([1 for i in range(0, len(a)) if a[i] > b[i]])
B = sum([1 for i in range(0, len(a)) if b[i] > a[i]])
Adding else as you do in your second code makes the syntax invalid.
For completeness, as #wim noted in the comment, the use of the ternary operator is unnecessary in your first code either because Boolean values in Python are simply integers of 1 and 0, so you can output the Boolean values returned by the comparison operators directly instead:
A = sum([i > j for i, j in zip(a, b)])
B = sum([j > i for i, j in zip(a, b)])

Getting Test Case Run time error

Im working on this question(not Homework)
Given a list of unsorted integers,A = {a1, a2, ...,an) can you find the pair of elements that have the smallest absolute difference between them? If there are multiple pairs, find them all.
This is what i came up with:
num = int(input())
array = [int(x) for x in input().split()]
diff = []
for i in range(len(array)):
for j in array:
diff.append(array[i]- j)
total = []
for i in diff:
if i > 0:
total.append(i)
grail = min(total)
holy = []
for i in range(len(array)):
for j in array:
if ((array[i] - j) == grail):
holy.append(array[i])
holy.append(j)
final = sorted(holy)
for item in final:
print(item, end = ' ')
This runs for few cases but gets runtime error on large inputs,any suggestion i might try?
Ex:
Input = [-20 -3916237 -357920 -3620601 7374819 -7330761 30 6246457 -6461594 266854 -520 -470 ]
Output = -520 -470 -20 30
Explanation = (-470) - (-520) = 30 - (-20) = 50, which is the smallest difference.
Thanks in advance
I did not bother to check your code for correctness because the implementation has complexity of O(n^2)
for i in range(len(array)):
for j in array:
if ((array[i] - j) == grail):
holy.append(array[i])
holy.append(j)
The required answer needs to have preferable complexity of O(log n). For achieving that you need to sort the list upfront.
from unittest import TestCase
import unittest
from sys import maxsize
from itertools import tee
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
def solution(n):
n = sorted(n)
pairs = []
diff = maxsize
for l, u in pairwise(n):
if u - l <= diff:
diff = u - l
pairs.append((diff, (l,u)))
pairs = sorted(pairs)
least = pairs[0][0]
return list(map(lambda x: x[1], filter(lambda x: x[0] == least, pairs)))
class TestLeastDiffrence(TestCase):
def testSimple(self):
n = [-20, -3916237, -357920, -3620601, 7374819, -7330761, 30, 6246457, -6461594, 266854, -520, -470]
self.assertEqual(solution(n),[(-520, -470), (-20, 30)])
if __name__ == '__main__':
unittest.main()

Return the subset of a list with the largest sum up to n recursively

def pack(L, n):
'''Return the subset of L with the largest sum up to n
>>> s = [4,1,3,5]
>>> pack(s, 7)
{3, 4}
>>> pack(s, 6)
{1, 5}
>>> pack(s, 11)
{1, 4, 5}
'''
I'm asked to code this. It takes in a list and an integer and returns the best combination to get that integer less than or equal to.
I used a helper function that takes in the sum, but it's not correct since I don't know how I could replace a number while in recursion.
# doesn't work as intended
def pack_helper(L, n, sum=0):
'''Return the subset of L with the largest sum up to n and the sum total
>>> s = [4,1,3,5]
>>> pack_helper(s, 7)
({3, 4}, 7)
>>> pack(s, 6)
({1, 5}, 6)
>>> pack(s, 11)
({1, 4, 5}, 10)
'''
package = set()
if L == []:
result = (package, sum)
else:
first = L[0]
(package, sum) = pack_helper(L[1:], n, sum)
if sum < n and (first + sum) <= n:
package.add(first)
sum = sum + first
return (package, sum)
Any hints or help? Thx
Here's a simple recursive function that does the job:
def pack(L, n):
'''Return the subset of L with the largest sum up to n
>>> s = [4,1,3,5]
>>> pack(s, 7)
{3, 4}
>>> pack(s, 6)
{1, 5}
>>> pack(s, 11)
{1, 4, 5}
'''
if all(j > n for j in L):
return set()
return max(({j} | pack(L[i+1:], n-j) for i, j in enumerate(L) if j <= n), key=sum)
If you're using Python 3, you can pass the default parameter to max instead:
def pack(L, n):
return max(({j} | pack(L[i+1:], n-j) for i, j in enumerate(L) if j <= n), key=sum, default=set())
The test data here is small enough that brute force is pretty fast. Recursion is not necessary:
from itertools import chain, combinations
# taken from the itertools documentation
def powerset(iterable):
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
def pack(L, n):
best_set, best_sum = (), 0
for candidate in powerset(L):
total = sum(candidate)
if best_sum < total <= n:
best_set, best_sum = candidate, total
return best_set
However, assuming positive weights, the dynamic programming solution is pretty short.
def pack(L, n):
assert all(w > 0 for w in L), 'weights must all be positive'
a = [((), 0)] * (n + 1)
for w in L:
a = [ (a[x - w][0] + (w,), a[x - w][1] + w)
if w <= x and a[x][1] < a[x - w][1] + w
else a[x] for x in range(n + 1) ]
return a[n][0]
How does this work?
a[x] stores the best set of weights processed so far that sum up to x or less (and the sum, just to save time). Before any weights have been processed, these are all empty ().
To process a new weight w at target x, one of the following two sets must be the best.
the best set of weights without this new weight that sum up to x (the old a[x]), or
the best set of weights without this new weight that sum up to x - w, plus this new weight w
Once all the weights are processed, the solution is right there at the end.
By the way, this is the well-known 0/1 knapsack problem. (The Wikipedia article currently has a solution that uses O(len(L) * n) time and O(len(L) * n) space, but it's doable in O(n) space, as I demonstrated here.)

How to find a missing number from a list?

How do I find the missing number from a sorted list the pythonic way?
a=[1,2,3,4,5,7,8,9,10]
I have come across this post but is there a more and efficient way to do this?
>>> a=[1,2,3,4,5,7,8,9,10]
>>> sum(xrange(a[0],a[-1]+1)) - sum(a)
6
alternatively (using the sum of AP series formula)
>>> a[-1]*(a[-1] + a[0]) / 2 - sum(a)
6
For generic cases when multiple numbers may be missing, you can formulate an O(n) approach.
>>> a=[1,2,3,4,7,8,10]
>>> from itertools import imap, chain
>>> from operator import sub
>>> print list(chain.from_iterable((a[i] + d for d in xrange(1, diff))
for i, diff in enumerate(imap(sub, a[1:], a))
if diff > 1))
[5, 6, 9]
This should work:
a = [1, 3, 4, 5, 7, 8, 9, 10]
b = [x for x in range(a[0], a[-1] + 1)]
a = set(a)
print(list(a ^ set(b)))
>>> [2, 6]
1 + 2 + 3 + ... + (n - 1) + n = (n) * (n + 1)/2
so the missing number is:
(a[-1] * (a[-1] + 1))/2 - sum(a)
set(range(a[len(a)-1])[1:]) - set(a)
Take the set of all numbers minus the set of given.
And another itertools way:
from itertools import count, izip
a=[1,2,3,4,5,7,8,9,10]
nums = (b for a, b in izip(a, count(a[0])) if a != b)
next(nums, None)
# 6
This will handle the cases when the first or last number is missing.
>>> a=[1,2,3,4,5,7,8,9,10]
>>> n = len(a) + 1
>>> (n*(n+1)/2) - sum(a)
6
If many missing numbers in list:
>>> a=[1,2,3,4,5,7,8,10]
>>> [(e1+1) for e1,e2 in zip(a, a[1:]) if e2-e1 != 1]
[6, 9]
def find(arr):
for x in range(0,len(arr) -1):
if arr[x+1] - arr[x] != 1:
print arr[x] + 1
Simple solution for the above problem, it also finds multiple missing elements.
a = [1,2,3,4,5,8,9,10]
missing_element = []
for i in range(a[0], a[-1]+1):
if i not in a:
missing_element.append(i)
print missing_element
o/p:
[6,7]
Here is the simple logic for finding mising numbers in list.
l=[-10,-5,2,4,5,9,20]
s=l[0]
e=l[-1]
x=sorted(range(s,e+1))
l_1=[]
for i in x:
if i not in l:
l_1.append(i)
print(l_1)
def findAllMissingNumbers(a):
b = sorted(a)
return list(set(range(b[0], b[-1])) - set(b))
L=[-5,1,2,3,4,5,7,8,9,10,13,55]
missing=[]
for i in range(L[0],L[-1]):
if i not in L:
missing.append(i)
print(missing)
A simple list comprehension approach that will work with multiple (non-consecutive) missing numbers.
def find_missing(lst):
"""Create list of integers missing from lst."""
return [lst[x] + 1 for x in range(len(lst) - 1)
if lst[x] + 1 != lst[x + 1]]
There is a perfectly working solution by #Abhiji. I would like to extent his answer by the option to define a granularity value. This might be necessary if the list should be checked for a missing value > 1:
from itertools import imap, chain
from operator import sub
granularity = 3600
data = [3600, 10800, 14400]
print list(
chain.from_iterable(
(data[i] + d for d in xrange(1, diff) if d % granularity == 0)
for i, diff in enumerate(imap(sub, data[1:], data))
if diff > granularity
)
)
The code above would produce the following output: [7200].
As this code snipped uses a lot of nested functions, I'd further like to provide a quick back reference, that helped me to understand the code:
Python enumerate()
Python imap()
Python chain.from_iterable()
Less efficient for very large lists, but here's my version for the Sum formula:
def missing_number_sum(arr):
return int((arr[-1]+1) * arr[-1]/2) - sum(arr)
If the range is known and the list is given, the below approach will work.
a=[1,2,3,4,5,7,8,9,10]
missingValues = [i for i in range(1, 10+1) if i not in a]
print(missingValues)
# o/p: [6]
set(range(1,a[-1])) | set(a)
Compute the union of two sets.
I used index position.
this way i compare index and value.
a=[0,1,2,3,4,5,7,8,9,10]
for i in a:
print i==a.index(i)

List Python Quantile

I'm making a Quantile problems and I need to do something like this
Intervals:
150-155
155-160
160-165
165-170
170-175
175-180
180-185
>> inferior_limit = 150
>> superior_limit = 185
>> range = inferior_limit - superior_limit
>> number_of_intervals = 5
Those are the variables
and I need that because I'm doing a table's interval
>> width = range/number_of_intervals
>> while inferior_limit <= superior_limit
# there is my problem
>> inferior_limit += width
>> print inferior_limit
Is this what you meant?
>>> inf, sup, delta = 150, 185, 5
>>> print '\n'.join('{}-{}'.format(x, x + delta) for x in xrange(inf, sup, delta))
150-155
155-160
160-165
165-170
170-175
175-180
180-185
>>> start, stop, step = 150, 185, 5
>>> r = range(start, stop + 1, step) # You can use xrange on py 2 for greater efficiency
>>> for x, y in zip(r, r[1:]):
print '{0}-{1}'.format(x, y)
150-155
155-160
160-165
165-170
170-175
175-180
180-185
A more efficient way of doing this is through the use of the itertools pairwise recipe.
from itertools import tee, izip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
for x, y in pairwise(r):
print '{0}-{1}'.format(x, y)
Also just for fun here is a solution using itertools.starmap, since nobody ever uses it!
from itertools import starmap
print '\n'.join(starmap('{0}-{1}'.format, pairwise(r)))

Categories

Resources