You are going to have to compare if each item of a list is contained in the other one; probably the most efficient iway to do this is to use sets() and extract their difference.
target_list = ["one", "two", "three", "four", "five"]
output_list = ['two','three','four', 'five']
print(set(target_list).difference(set(output_list)))
output:
set(['one'])
Answer from Reblochon Masque on Stack OverflowYou are going to have to compare if each item of a list is contained in the other one; probably the most efficient iway to do this is to use sets() and extract their difference.
target_list = ["one", "two", "three", "four", "five"]
output_list = ['two','three','four', 'five']
print(set(target_list).difference(set(output_list)))
output:
set(['one'])
You can find the missing elements by using Counter. Every missing element has its occurrence.
from collections import Counter
target_list = ["one", "two", "three", "four", "five"]
output_list = ['two','three','four', 'five']
Counter(target_list)-Counter(output_list)
Output:
Counter({'one': 1})
>>> 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]
If there is no duplicates in given lists you may use sets and their "-" operator:
list1 = ['1.1.1.1/24', '2.2.2.2/24', '3.3.3.3/24', '4.4.4.4/24']
list2 = ['3.3.3.3/24', '4.4.4.4/24', '5.5.5.5/24', '6.6.6.6/24']
set1 = set(list1)
set2 = set(list2)
missing = list(sorted(set1 - set2))
added = list(sorted(set2 - set1))
print('missing:', missing)
print('added:', added)
this prints
missing: ['1.1.1.1/24', '2.2.2.2/24']
added: ['5.5.5.5/24', '6.6.6.6/24']
With sets you can compare lists:
missing = set(list1_original).difference(list2)
added = set(list2).difference(list1_original)
Keep in mind that the output is a set. To cast the output into a list you can use list(missing).
You need to be aware that i < len(A) is causing some problem.
Given this example:
A = [1, 2, 3, 5]
It looks pretty clear that the desired answer is 4, but your function is giving None. It's because len(A) == 4 and thus, your loop condition is i < 4, which effectively enumerates i from 1 to 3.
Since you want to find out the missing number, you might as well stop the loop when i reaches the largest number in the list, rather than the length of the list, so:
while i < max(A):
would be right.
Find missing numbers
Using range(start, stop) we can build a sorted list which already contains all the numbers. Now it's just matter of finding the missing values in your list.
Our range will be made using the lower and higher values of your list. range(min(A), max(A)).
def solution(A):
missings = []
for n in range(min(A), max(A)): # Iterate over each number in the sorted and complete list.
if n not in A: # If that number isn't in your list.
missings.append(n)
return missings
Or as a list comprehension in one line:
def solution(A): return [n for n in range(min(A), max(A)) if n not in A]
Example:
>>> solution([1, 9, 4, 3, 11, 5, 7])
[2, 6, 8, 10]
Find non-negative missing numbers
But you said "find a missing positive integer", so you don't want negatives ones.
Just change the min(A) part of range(min(A), max(A)) to range(max(0, min(A)), max(A)).
max(0, min(A)) will use max to give you the bigger number between 0 and your lower actual value, so negative ones are replaced by 0.
Example:
>>> solution([-4, -5, 1, 9])
[0, 2, 3, 4, 5, 6, 7, 8]
Find non-negative missing number after the lower non-negative number
But as said before, you only said: "find a missing positive integer", so at first, I understood you don't want negatives ones.
But, what if you only want the missing (as my first idea) non-negative values (as the second idea) after the lower non-negative value (new idea)?
Easy!
Just change the min(A) part of range(min(A), max(A)) to range(min([n for n in A if n >= 0]), max(A)).
min([n for n in A if n >= 0]) will look for the lower non-negative value in your list.
Example:
>>> solution([-4, -5, 3, 9])
[4, 5, 6, 7, 8]
Take the difference between the sets:
set(range(min(L),max(L))) - set(L)
If you are really crunched for time and L is truly sorted, then
set(range(L[0], L[-1])) - set(L)
This function should do the trick
def missing_elements(L):
s, e = L[0], L[-1]
return sorted(set(range(s, e + 1)).difference(L))
miss = missing_elements(L)
If the input sequence is sorted, you could use sets here. Take the start and end values from the input list:
def missing_elements(L):
start, end = L[0], L[-1]
return sorted(set(range(start, end + 1)).difference(L))
This assumes Python 3; for Python 2, use xrange() to avoid building a list first.
The sorted() call is optional; without it a set() is returned of the missing values, with it you get a sorted list.
Demo:
>>> L = [10,11,13,14,15,16,17,18,20]
>>> missing_elements(L)
[12, 19]
Another approach is by detecting gaps between subsequent numbers; using an older itertools library sliding window recipe:
from itertools import islice, chain
def window(seq, n=2):
"Returns a sliding window (of width n) over data from the iterable"
" s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ... "
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
def missing_elements(L):
missing = chain.from_iterable(range(x + 1, y) for x, y in window(L) if (y - x) > 1)
return list(missing)
This is a pure O(n) operation, and if you know the number of missing items, you can make sure it only produces those and then stops:
def missing_elements(L, count):
missing = chain.from_iterable(range(x + 1, y) for x, y in window(L) if (y - x) > 1)
return list(islice(missing, 0, count))
This will handle larger gaps too; if you are missing 2 items at 11 and 12, it'll still work:
>>> missing_elements([10, 13, 14, 15], 2)
[11, 12]
and the above sample only had to iterate over [10, 13] to figure this out.
Assuming that L is a list of integers with no duplicates, you can infer that the part of the list between start and index is completely consecutive if and only if L[index] == L[start] + (index - start) and similarly with index and end is completely consecutive if and only if L[index] == L[end] - (end - index). This combined with splitting the list into two recursively gives a sublinear solution.
# python 3.3 and up, in older versions, replace "yield from" with yield loop
def missing_elements(L, start, end):
if end - start <= 1:
if L[end] - L[start] > 1:
yield from range(L[start] + 1, L[end])
return
index = start + (end - start) // 2
# is the lower half consecutive?
consecutive_low = L[index] == L[start] + (index - start)
if not consecutive_low:
yield from missing_elements(L, start, index)
# is the upper part consecutive?
consecutive_high = L[index] == L[end] - (end - index)
if not consecutive_high:
yield from missing_elements(L, index, end)
def main():
L = [10,11,13,14,15,16,17,18,20]
print(list(missing_elements(L,0,len(L)-1)))
L = range(10, 21)
print(list(missing_elements(L,0,len(L)-1)))
main()