Search one smaller and one bigger number then serach term? - python

I have a list in the python and I want to find out the search term with conditions one smaller and one bigger number the search term.
list = [2, 3, 5, 7, 9, 12, 19, 22, 34]
search_term = 10
I want to get one smaller and one bigger term next to the search term from the list.
The expected result should be
output = [7, 9]

Edit for [7, 9]
Search up until you are >= search_term, then print last 2 values:
# Don't use class names (list) as variables
lst = [2, 3, 5, 7, 9, 12, 19, 22, 34]
search_term = 10
# Sort list for iterating. lst is now sorted
lst.sort()
index = 0
# Get index of values. Stop when item >= search_term
for i, item in enumerate(lst[1:]):
if item >= search_term:
index = i
break
output = [lst[index-1], lst[index]]
>>> output
[7, 9]
This was for printing value before and after search_term
There was no output, and this was a guess at what OP wanted
You can iterate over your lst and check for > and < search_term:
This works for non-empty lists
# Don't use class names (list) as variables
lst = [2, 3, 5, 7, 9, 12, 19, 22, 34]
search_term = 10
# Sort
lst.sort()
last = lst[0]
index = 0
# Get item before
for i, item in enumerate(lst[1:]):
if item < search_term:
last = item
index = i
else:
break
print(f'Before = {last}')
# Get item after
try:
for item in lst[index+1:]:
if item >= search_term:
last = item
break
except IndexError:
pass
# You don't have any values after the before value
print(f'After = {last}')
Before = 9
After = 12
An exception may be the case of:
>>> lst = [1, 10]
>>> search_term = 10
Which prints
Before = 1
After = 10

Code:
l = [2, 3, 5, 7, 9, 12, 19, 22, 34]
search_term = 10
tmp = [max([t for t in l if t <= search_term])] # smaller than search
tmp.append(min([t for t in l if t >= search_term])) #bigger than search
print("nearest smaller :",tmp[0])
print("nearest bigger :",tmp[1])
Output:
nearest smaller : 9
nearest bigger : 12

Related

Python produce alternative numbers list from a list of n numbers

I have a list of n numbers. I want to group them in g groups. Also, I want to reverse elements in every odd group. Finally, I would combine all elements in even and odd groups into a new sublist. First I am giving what answer I am expecting and where I went wrong:
Expected answer:
num = 14
grp = 4
# A list of num natural numbers arranged in group (row) of 4 numbers
lst =
[0,1,2,3,
4,5,6,7,
8,9,10,11,
12,13]
lst =
[[0,1,2,3],
[4,5,6,7],
[8,9,10,11],
[12,13]]
# Reverse elements in odd rows
newlst =
[[0,1,2,3],
[7,6,5,4], # reversed here
[8,9,10,11],
[13,12]] # reversed here
# combine elements in all sublists by their position
# combine first element in all sublists into a new sublist
sollst =
[[0,7,8,13],[1,6,9,12],[2,5,10],[3,4,11]]
My solution:
num = 14
grp = 4
#### print
lst= list(range(0,num,1))
newlst= [lst[i:i+grp:1] for i in range(0,num,grp)]
evnlst = newlst[0::2]
oddlst = newlst[1::2]
newoddlst = [oddlst [i][::-1] for i in range(len(oddlst))]
sollst= evnlst + newoddlst
# This gives [[0, 1, 2, 3], [8, 9, 10, 11], [7, 6, 5, 4], [13, 12]]
from itertools import zip_longest
print([[x for x in t if x is not None] for t in zip_longest(fevngps)])
Present answer:
I reached the one step before the final answer and now I have to combine the lists of different lengths and I am running into an error
TypeError: 'int' object is not subscriptable
One approach:
from itertools import zip_longest
num = 14
grp = 4
lst = list(range(0, num, 1))
newlst = [lst[i:i + grp:1] for i in range(0, num, grp)]
# build new list where the sub-list are reversed if in odd indices
revlst = [lst[::-1] if i % 2 == 1 else lst for i, lst in enumerate(newlst)]
# zip using zip_longest and filter out the None values (the default fill value of zip_longest)
result = [[v for v in vs if v is not None] for vs in zip_longest(*revlst)]
print(result)
Output
[[0, 7, 8, 13], [1, 6, 9, 12], [2, 5, 10], [3, 4, 11]]

Watching a counter, tally total and counting missed counts

I am attempting to create a piece of code that will watch a counter with an output something like:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
I want the code to be able to tally the total and tell me how many counts are missed for example if this happened:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25, 26, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,1,2]
I would get a total of 92 still, but get feedback that 8 are missing.
I have gotten very close with the following code:
Blk_Tot = 0
CBN = 0
LBN = 0
x = 0
y = 0
z = 0
MissedBlocks = 0
for i in range(len(a1)):
CBN = a1[i]
if CBN - LBN <= 0:
if LBN == 30:
y = 30 - abs(CBN - LBN)
elif LBN < 30:
z = 30 - LBN
y = 30 - abs(CBN - LBN) + z
print(z)
Blk_Tot = Blk_Tot + y
else:
x = CBN - LBN
Blk_Tot = Blk_Tot + x
if x > 1:
MissedBlocks = MissedBlocks - 1 + x
LBN = CBN
print(Blk_Tot)
print(MissedBlocks)
If I delete anywhere between 1 and 30 it works perfectly, however if I delete across 30, say 29,30,1,2 it breaks.I don't expect it to be able to miss 30 in a row and still be able to come up with a proper total however.
Anyone have any ideas on how this might be achieved? I feel like I am missing an obvious answer :D
Sorry I think I was unclear, a1 is a counter coming from an external device that counts from 1 to 30 and then wraps around to 1 again. Each count is actually part of a message to show that the message was received; so say 1 2 4, I know that the 3rd message is missing. What I am trying to do is found out the total that should have been recieved and how many are missing from the count.
Update after an idea from the posts below, another method of doing this maybe:
Input:
123456
List[1,2,3,4,5,6]
1.Check first input to see which part of the list it is in and start from there (in case we don't start from zero)
2.every time an input is received check if that matches the next value in the array
3.if not then how many steps does it take to find that value
You don't need to keep track if you past the 30 line.
Just compare with the ideal sequence and count the missing numbers.
No knowledge if parts missing at the end.
No knowledge if more than 30 parts are missing in a block.
from itertools import cycle
def idealSeqGen():
for i in cycle(range(1,31)):
yield(i)
def receivedSeqGen():
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1,2]
for i in a1:
yield(i)
receivedSeq = receivedSeqGen()
idealSeq = idealSeqGen()
missing = 0
ideal = next(idealSeq)
try:
while True:
received = next(receivedSeq)
while received != ideal:
missing += 1
ideal = next(idealSeq)
ideal = next(idealSeq)
except StopIteration:
pass
print (f'There are {missing} items missing')
Edit
The loop part can be a little bit simpler
missing = 0
try:
while True:
ideal = next(idealSeq)
received = next(receivedSeq)
while received != ideal:
missing += 1
ideal = next(idealSeq)
except StopIteration:
pass
print (f'There are {missing} items missing')
In general, if you want to count the number of differences between two lists, you can easily use a dictionary. The other answer would also work, but it is highly inefficient for even slightly larger lists.
def counter(lst):
# create a dictionary with count of each element
d = {}
for i in lst:
if d.get(i, None):
d[i] += 1
else:
d[i] = 1
return d
def compare(d1, d2):
# d1 and d2 are dictionaries
ans = 0
for i in d1.values():
if d2.get(i, None):
# comapares the common values in both lists
ans += abs(d1[i]-d2[i])
d2[i] = 0
else:
#for elements only in the first list
ans += d1[i]
for i in d2.values():
# for elements only in the second list
if d2[i]>0:
ans += d2[i]
return ans
l1 = [...]
l2 = [...]
print(compare(counter(l1), counter(l2)))
New code to check for missing elements from a repeating sequence pattern
Now that I have understood your question more clearly, here's the code. The assumption in this code is the list will always be in ascending order from 1 thru 30 and then repeats again from 1. There can be missing elements between 1 and 30 but the order will always be in ascending order between 1 and 30.
If the source data is as shown in list a1, then the code will result in 8 missing elements.
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1,2]
a2 = a1.copy()
c = 1
missing = 0
while a2:
if a2[0] == c:
c+=1
a2.pop(0)
elif a2[0] > c:
missing +=1
c+=1
elif a2[0] < c:
missing += 31-c
c = 1
if c == 31: c=1
print (f'There are {missing} items missing in the list')
The output of this will be:
There are 8 items missing in the list
Let me know if this addresses your question
earlier code to compare two lists
You cannot use set as the items are repeated. So you need to sort them and find out how many times each element is in both lists. The difference will give you the missing counts. You may have an element in a1 but not in a2 or vice versa. So finding out the absolute count of missing items will give you the results.
I will update the response with better variables in my next update.
Here's how I did it:
code with comments:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,1,2]
#step 1: Find out which list is longer. We will use that as the master list
if len(a1) > len(a2):
master_list = a1.copy()
second_list = a2.copy()
else:
master_list = a2.copy()
second_list = a1.copy()
#step 2: We must sort both master and second list
# so we can compare against each other
master_list.sort()
second_list.sort()
#set the counter to zero
missing = 0
#iterate through the master list and find all values in master against second list
#for each iteration, remove the value in master[0] from both master and second list
#when you have iterated through the full list, you will get an empty master_list
#this will help you to use while statement to iterate until master_list is empty
while master_list:
#pick the first element of master list to search for
x = master_list[0]
#count the number of times master_list[0] is found in both master and second list
a_count = master_list.count(x)
b_count = second_list.count(x)
#absolute difference of both gives you how many are missing from each other
#master may have 4 occurrences and second may have 2 occurrences. abs diff is 2
#master may have 2 occurrences and second may have 5 occurrences. abs diff is 3
missing += abs(a_count - b_count)
#now remove all occurrences of master_list[0] from both master and second list
master_list = [i for i in master_list if i != x]
second_list = [i for i in second_list if i != x]
#iterate until master_list is empty
#you may end up with a few items in second_list that are not found in master list
#add them to the missing items list
#thats your absolute total of all missing items between lists a1 and a2
#if you want to know the difference between the bigger list and shorter one,
#then don't add the missing items from second list
missing += len(second_list)
#now print the count of missig elements between the two lists
print ('Total number of missing elements are:', missing)
The output from this is:
Total number of missing elements are: 7
If you want to find out which elements are missing, then you need to add a few more lines of code.
In the above example, elements 27,28,29,30, 4, 5 are missing from a2 and 31 from a1. So total number of missing elements is 7.
code without comments:
a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
5, 6, 7, 8, 9, 10, 11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,1,2]
if len(a1) > len(a2):
master_list = a1.copy()
second_list = a2.copy()
else:
master_list = a2.copy()
second_list = a1.copy()
master_list.sort()
second_list.sort()
missing = 0
while master_list:
x = master_list[0]
a_count = master_list.count(x)
b_count = second_list.count(x)
missing += abs(a_count - b_count)
master_list = [i for i in master_list if i != x]
second_list = [i for i in second_list if i != x]
missing += len(second_list)
print ('Total number of missing elements are:', missing)

how to returns the index of the smallest element in the list in python

In my code, returns the position of the smallest element in the list by use index() function, when I run the code, it run nothing. Please help me to figure out problem. Here is what I coded:
def get_index_of_smallest(numbers):
smallest_index = []
for element in range (len(numbers)):
element = numbers.index(min(numbers))
smallest_index = element + 1
return smallest_index
def test_get_index_of_smallest():
list1 = [23, 3, 6, 5, 12, 9, 7, 4]
print(get_index_of_smallest(list1))
Many thanks.
You can use min(list) and builtin function of list(list.index())
list1 = [23, 3, 6, 5, 12, 9, 7, 4]
min_num = min(list1)
index = list1.index(min_num)
One way, it's possible using min, emumerate and lambda
myList = [23, 3, 6, 5, 12, 9, 7, 4]
min(enumerate(myList), key=lambda x:x[1])[0]
#1
Your code looks good, but you forgot to call the function. Add test_get_index_of_smallest(), and it will work!
Input:
def get_index_of_smallest(numbers):
smallest_index = []
for element in range (len(numbers)):
element = numbers.index(min(numbers))
smallest_index = element + 1
return smallest_index
def test_get_index_of_smallest():
list1 = [23, 3, 6, 5, 12, 9, 7, 4]
print(get_index_of_smallest(list1))
test_get_index_of_smallest()
Output:
2
Edit:
You can further cut down your code. Here is a code that does the same thing:
Input:
def get_index_of_smallest(numbers):
return numbers.index(min(numbers))+1
print(get_index_of_smallest([23, 3, 6, 5, 12, 9, 7, 4]))
Output:
2
We can use list comprehension and enumerate here
min_idx = [idx for idx, item in enumerate(list1) if item == min(list1)]
[1]
Here is a expanded version of what is going on here
for idx, item in enumerate(list1):
if item == min(list1):
min_idx = idx
When we enumerate in it iterates for the index and item so what we can do is check each item v min(list1) if we get a match we can set our min_idx variable to the corresponding index of that item, cheers !

To obtain a range of particular value form a list

Objective:
To obtain sum of the integers from a list, except ignore sections of numbers starting with a 6 and extending to the next 9 (every 6 will be followed by at least one 9). Return 0 for no numbers.
Input Master List
a=[4, 5, 6, 7, 9,2, 6,8,9]
My code so far
z6_ind=[]
z9_ind=[]
z69_ind=[]
x=None
for i,v in enumerate(a):
if v==6:
z6_ind.append(i)
if v==9:
z9_ind.append(i)
print(z6_ind. z9_ind)
My idea is to obtain the indexes of the master list in terms of separate lists (eg. z6_ind, z9_ind and finally the problematic z69_ind which should contain the range in terms of [[2,4],[6,8]] that should be excluded from the master list while sum calculation.
From above script, it gives z9_ind equals to [4, 8] whereas z6_ind equals to [2, 6].
Thanks !
I am not sure if I caught it correctly, but do you want this code?
a = [4, 5, 6, 7, 9, 2, 6, 8, 9]
sigma = 0
exc_ind = []
flag = False
for ind, item in enumerate(a):
if item == 6 and not flag:
flag = True
exc_ind.append([])
exc_ind[-1].append(ind)
elif item == 9 and flag:
exc_ind[-1].append(ind)
flag = False
elif not flag:
sigma += item
print(sigma)
print(exc_ind)
The result:
11
[[2, 4], [6, 8]]
A verbose version with generator:
a=[4, 5, 6, 7, 9,2, 6,8,9]
def iterate(iterable):
stop = False
for i in iterable:
if i == 6:
if stop == False:
stop = True
continue
elif i == 9:
if stop == True:
stop = False
continue
if stop == False:
yield i
print(sum(iterate(a))) # will sum 4, 5 and 2
Prints:
11
If you want to use the part of your code:
a_sum = sum(a)
to_reduce = 0
for (bot,top) in zip(z6_ind, z9_ind):
to_reduce += sum(a[bot:top+1])
Basically zip "pairs" both indexes and get sums between them - numbers you want to reduce a_sum by:
result = a_sum - to_reduce
You can do the following:
import numpy as np
a=np.array([4, 5, 6, 7, 9,2, 6,8,9])
ind1 = np.where(a == 6)[0]
ind2 = np.where(a == 9)[0]
indices = [item for i in zip(ind1, ind2) for item in np.arange(i[0], i[1]+1)]
result = sum(a) - sum(a[indices])
print (result)
Output
11

Inserting element Python

lst=[5,6,7,8,9]
v=10
for item in lst:
if item<v:
lst.insert(0,v)
print(lst)
i want to insert 10, at the index 0 if all the elements in the list are under 10, im not tryning to insert 10 each time
so it should look like this : [10,5,6,7,8,9]
You are inserting the same value of v at the beginning of the original list based on how many of the original values are less than v. In this case, preservation of insertion order is moot.
All inserted values are the same and are prepended to an original list that doesn't change.
So why not use something this
lst = [5, 6, 7, 8, 9]
v = 10
count = 0
for item in lst:
if item < v:
count += 1
new_lst = [v] * count + lst
print(new_lst)
Result
>>> [10, 10, 10, 10, 10, 5, 6, 7, 8, 9]
Edit: Updating answer based on further clarification
i want to insert 10, at the index 0 if all the elements in the
list are under 10, im not tryning to insert 10 each time
lst = [5, 6, 7, 8, 9]
v = 10
for item in lst[:]:
if item < v:
lst.insert(0, v)
break
print(lst)
Result
>>> [10, 5, 6, 7, 8, 9]
The updated code will insert v at index 0 only once if a single item is less than v. When the item < v condition is met the for loop ends without checking any of the remaining items. Otherwise, if None of the values are less than v, you will traverse the entirety of your list without making any changes.
Notice that I used the insert method here since this code will shift all of your lst items only once.

Categories