Related
I am a beginner in programming. I saw the challenge about missing numbers on Geeks for Geeks. The solutions offered are quite complex for me. I wonder if my solution is correct because it seems too easy. Thanks!
A = [1, 2, 3, 4, 5, 7]
def missing():
for i in range (len(A)):
if A[i+1] != A[i] + 1:
return A[i] + 1
missing()
This is your example but with list comprehension. This will allow you to return a list of all the missing numbers. Keep in mind your sollution only works for gaps == 1.
A = [1, 3, 4, 5, 7]
def missing(A):
x = [A[i] + 1 for i in range (len(A)-1) if A[i+1] != A[i] + 1]
return x
print(missing(A))
output
[2, 6]
I would say that your code is quite unstable, but it may work.
I would say this is working better
A = [1, 2, 3, 4, 5, 7]
def missing():
for i in range(len(A)):
result = 0
if A[i+1] != A[i] + 1:
result A[i] + 1
return result
missing()
But also what if 1 is the missing number?
This code below allows 1 to be the missing number
A = [1, 2, 3, 4, 5, 7]
def missing():
if A[0] != 1:
result = 1
return result
for i in range(len(A)):
result = 0
if A[i+1] != A[i] + 1:
result A[i] + 1
return result
missing()
You can just check that each number in the range of numbers from the first element in the list to the last element in the list exists in the list.
for Loop:
>>> def missing_num(numlist):
numlist.sort()
missing = []
for i in range(numlist[0], numlist[-1]+1):
if i not in numlist:
missing.append(i)
return missing
>>> missing_num([1, 2, 3, 4, 5, 7])
[6]
List Comprehension:
>>> def missing_num(numlist):
numlist.sort()
nums = list(range(numlist[0], numlist[-1]+1))
return [i for i in nums if i not in numlist]
>>> missing_num([1, 2, 3, 4, 5, 7])
[6]
With some randomized lists:
>>> for _ in range(5):
randlist = random.sample(list(range(10)), 7)
print(randlist, missing_num(randlist))
[1, 2, 3, 4, 5, 7, 9] [6, 8]
[0, 1, 2, 5, 6, 7, 8] [3, 4]
[0, 1, 3, 4, 5, 6, 9] [2, 7, 8]
[2, 4, 5, 6, 7, 8, 9] [3]
[0, 2, 3, 4, 5, 7, 8] [1, 6]
What is a fast way to get index of only neighboring repeating elements within a Python list?
# Have
list1 = [2, 2, 2, 3, 5, 6, 6, 6]
# 0 1 2 5 6 7
# Want
index = [0, 1, 2, 5, 6, 7]
A set will be very handy to avoid having duplicates, and once you have the indices you can covert it back to a list and sort it, so try the following:
# Have
list1 = [2, 2, 2, 3, 5, 6, 6, 6]
# 0 1 2 5 6 7
result = set()
for i in range(1, len(list1)):
if list1[i - 1] == list1[i]:
result.add(i - 1)
result.add(i)
index = sorted(list(result))
easy in pandas
import pandas as pd
df = pd.DataFrame(list1)
ids = df.index[(df[0].diff() == 0) | (df[0].diff(-1) == 0)].values
output:
array([0, 1, 2, 5, 6, 7])
Here's an O(n) solution. Based upon #lmiguelvargasf 's answer.
list1 = [2, 2, 2, 3, 5, 6, 6, 6]
# 0 1 2 5 6 7
index = []
last = False
for i in range(1, len(list1)):
if list1[i - 1] != list1[i]:
last = False
elif last:
index.append(i)
last = True
else:
index.append(i - 1)
index.append(i)
last = True
Your result will be sorted. Pretty sure this is as quick as it gets :D.
Not as short and clean but definitely fast.
You can use itertools.groupby to handle the grouping of neighbouring repeated elements:
from itertools import groupby
list1 = [2, 2, 2, 3, 5, 6, 6, 6]
index, i = [], 0
for k, g in groupby(list1):
grp = len(list(g))
if grp > 1:
index.extend(range(i, i+grp))
i += grp
else:
i += 1
print(index)
# [0, 1, 2, 5, 6, 7]
After figuring out for a while, I came out with a fast way using numpy without using slower nested for loops:
(Improving solution thanks to answer below from #lmiguelvargasf)
dup_ix = [(i, i-1) for i in range(1, len(list1)) if list1[i] == list1[i-1]]
dup_ix = np.array(dup_ix).flatten()
dup_ix = list(set(dup_ix))
print(dup_ix)
[0, 1, 2, 5, 6, 7]
I have an unordered list of numbers
num_list=[3 4 5 1 2 5 6 3 1 2 6 9]
I want to run through the list and remove all numbers that are smaller than the previous such that the list is ordered in ascending order after deleting such numbers. How can I do that?
Expected output:
num_list=[3 4 5 5 6 6 9]
One simple approach would be to iteratively add values from num_list to a new list if they satisfy the condition of being greater than the last appended value:
out = [num_list[0]]
for i in num_list[1:]:
if i >= out[-1]:
out.append(i)
print(out)
# [3, 4, 5, 5, 6, 6, 9]
Short approach with functools.reduce function:
import functools
num_list = [3,4,5,1,2,5,6,3,1,2,6,9]
res = functools.reduce(lambda x, y: x if y < x[-1] else x + [y],
num_list[1:], [num_list[0]])
print(res)
The output:
[3, 4, 5, 5, 6, 6, 9]
A simple approach using list.pop
num_list = [3, 4, 5, 1, 2, 5, 6, 3, 1, 2, 6, 9]
i = 1
while (i < len(num_list)):
if num_list[i] < num_list[i - 1]:
num_list.pop(i)
else:
i += 1
print(num_list)
# [3, 4, 5, 5, 6, 6, 9]
A comprehension could be used for this:
num_list = [3, 4, 5, 1, 2, 5, 6, 3, 1, 2, 6, 9]
(x for i, x in enumerate(num_list) if all(x >= j for j in num_list[:i]))
Though it's not as efficient as yatu's answer.
Version with itertools.groupby:
from itertools import groupby
num_list=[3, 4, 5, 1, 2, 5, 6, 3, 1, 2, 6, 9]
out = [num_list[0]]
[out.extend(g) for v, g in groupby(num_list[1:], lambda k: k>=out[-1]) if v]
print(out)
Prints:
[3, 4, 5, 5, 6, 6, 9]
Here is another one-liner solution using itertools.accumulate.
from itertools import accumulate
result = [n for n, cur_max in zip(l, accumulate(l, max)) if n >= cur_max]
Despite being concise, it is actually much less efficient than the following solution using an explicit for loop. This is also the most efficient solution as of now.
cur_max = l[0]
result = []
for e in l:
if e >= cur_max:
cur_max = e
result.append(e)
Here I have a list
a = [1, 2, 1, 4, 5, 7, 8, 4, 6]
Now I want a following output but without for loop.
Remove all the duplicate from the list.
[2, 5, 7, 8, 6]
output list contain only single occurrence number
Given: a = [1, 2, 1, 4, 5, 7, 8, 4, 6]
One liner:
b = [x for x in a if a.count(x) == 1]
You can use a Counter and a conditional list comprehension or filter in order to maintain the original order:
from collections import Counter
c = Counter(a)
clean_a = filter(lambda x: c[x] == 1, a) # avoids 'for' ;-)
# clean_a = list(filter(lambda x: c[x] == 1, a)) # Python3, if you need a list
# clean_a = [x for x in a if c[a] == 1] # would be my choice
This is a very simple and inefficient implementation.
We use a while loop to access every element of a. In the loop we check if the current element appears only once in the list. If yes, we add it to a new list.
a = [1, 2, 1, 4, 5, 7, 8, 4, 6]
index = 0
result = []
while index < len(a):
if a.count(a[index]) == 1:
result.append(a[index])
index += 1
print(result)
def cleaner(LIST, pos):
if len(LIST)>pos:
if LIST[pos] in LIST[pos+1:]:
LIST.pop(pos)
# OR
# LIST.remove(LIST[pos])
cleaner(LIST, pos)
else:
pos+=1
cleaner(LIST, pos)
return LIST
LIST = [1, 2, 1, 4, 5, 7, 8, 4, 6]
print(cleaner(LIST, 0))
Here are examples:
given: 1,2,3 [list or range of numbers]
return: 2,1,3 [reordered list]
given: 1,2,3,4,5
return: 3 1 5 2 4
given: 1,2,3,4,5,6,7
return: 4 1 7 2 6 3 5 OR 4 7 1 5 3 2 6 or similar
given: 1,2,4,5,6,7,8,9
return: 5,1,9,3,7,2,8,4,6 or similar
In rendering you start with the center, then the most extreme cases, and become more and more detailed. This is NOT random. I'm in python, but theres got to be a name for this in comp sci. Help appreciated.
Edit to add
even case -
given: 1234
return: 2,1,4,3 OR 3,1,4,2 OR 2,4,1,3 OR 3,4,1,2
A valid, although ungraceful solution:
def sigorder(lst):
result = []
l = len(lst)
if l <= 2:
return lst
if l > 2:
result.append(lst[l/2])
result.append(lst[0])
result.append(lst[-1])
right = sigord(lst[l/2+1:-1])
left = sigord(lst[1:l/2])
result.extend(slicezip(left, right))
return result
Inner, recursive function:
def sigord(lst):
result = []
if len(lst) < 3:
return lst
else:
l = len(lst)
result.append(lst[l/2])
left = sigord(lst[0:l/2])
right = sigord(lst[l/2 + 1:len(lst)])
result.extend(slicezip(left, right))
return result
slicezip() (Note: conveniently handles the potential unevenness of the left/right lists automagically)
def slicezip(a, b):
result = [0]*(len(a)+len(b))
result[::2] = a
result[1::2] = b
return result
Outputs for lists length 4-9 :
[3, 1, 4, 2]
[3, 1, 5, 2, 4]
[4, 1, 6, 2, 5, 3]
[4, 1, 7, 2, 5, 3, 6]
[5, 1, 8, 3, 6, 2, 7, 4]
[5, 1, 9, 3, 7, 2, 6, 4, 8]
This should do it:
def extreme_cases(upd_itrr, new_itrr):
new_itrr.append(min(upd_itrr))
new_itrr.append(max(upd_itrr))
upd_itrr.remove(min(upd_itrr))
upd_itrr.remove(max(upd_itrr))
if len(upd_itrr) >= 2:
extreme_cases(upd_itrr, new_itrr)
return upd_itrr, new_itrr
def reordered_range(itr):
new_itr = []
center = 0
if len(itr) % 2 != 0:
center = itr[len(itr) // 2]
elif len(itr) % 2 == 0:
center = itr[(len(itr) // 2) - 1]
new_itr.append(center)
upd_itr = itr[:]
upd_itr.remove(center)
upd_itr, new_itr = extreme_cases(upd_itr, new_itr)
if upd_itr:
new_itr.append(upd_itr[0])
return new_itr
print(reordered_range([1, 2, 3]))
print(reordered_range([1, 2, 3, 4]))
print(reordered_range([1, 2, 3, 4, 5]))
print(reordered_range([1, 2, 3, 4, 5, 6, 7]))
print(reordered_range([1, 2, 4, 5, 6, 7, 8, 9]))
Output:
[2, 1, 3]
[2, 1, 4, 3]
[3, 1, 5, 2, 4]
[4, 1, 7, 2, 6, 3, 5]
[5, 1, 9, 2, 8, 4, 7, 6]
Another solution:
import numpy as np
from copy import copy
def bisecting_order(lst):
# bisecting order of an unordered list
result = []
l = len(lst)
if l < 3:
return lst
result.append(closest(lst,np.mean(lst)))
result.append(min(lst))
result.append(max(lst))
# get bisections
while len(result)!=len(lst):
temp_list = copy(result)
temp_list.sort()
for i in xrange(len(temp_list)-1):
newnum = closest(lst,np.mean([temp_list[i],temp_list[i+1]]))
if newnum in result:
continue
else:
result.append(newnum)
return result
def closest(mylist,mynum):
return min(mylist, key=lambda x:abs(x-mynum))