Python3 - closest previous and next element in a list (treated as cyclic) with a valid value - python-3.x

I have a list of values... some are valid, some not, the invalid contain None. I test each element for validity. When I find an invalid element, I need to find indexes of the closest previous and the closest next valid value. I need to treat the list as a cycle, so if there are no valid elements before/after the initial element, it should search from the end/start of the list... This way, if there is at least one valid value in the list, both the previous and the next valid value will be found (it can be the same index, if there is only one valid value in the list).
Ok, it is complicated to explain and it gets very complicated when I try to code it. But I am sure there is some simple and idiomatical way to do it. Can you help me?

Neither I am a programmer, but I use something like this for analysing data around the 24-hour clock (that means, for example 23:00 is before 01:00 etc.). Then I compute the unknown values as a weighted averages of the previous and next known values. The parameters are the position of the unknown element in the list and the list itself:
def get_prev_known(i, some_list):
for j, item in enumerate(some_list[i::-1]+some_list[:i:-1]):
if j > 0 and item is not None:
return (i-j) % len(some_list)
def get_next_known(i, some_list):
for j, item in enumerate(some_list[i:]+some_list[:i]):
if j > 0 and item is not None:
return (i+j) % len(some_list)
it should solve your problem.

Related

Palindrome problem - Trying to check 2 lists for equality python3.9

I'm writing a program to check if a given user input is a palindrome or not. if it is the program should print "Yes", if not "no". I realize that this program is entirely too complex since I actually only needed to check the whole word using the reversed() function, but I ended up making it quite complex by splitting the word into two lists and then checking the lists against each other.
Despite that, I'm not clear why the last conditional isn't returning the expected "Yes" when I pass it "racecar" as an input. When I print the lists in line 23 and 24, I get two lists that are identical, but then when I compare them in the conditional, I always get "No" meaning they are not equal to each other. can anyone explain why this is? I've tried to convert the lists to strings but no luck.
def odd_or_even(a): # function for determining if odd or even
if len(a) % 2 == 0:
return True
else:
return False
the_string = input("How about a word?\n")
x = int(len(the_string))
odd_or_even(the_string) # find out if the word has an odd or an even number of characters
if odd_or_even(the_string) == True: # if even
for i in range(x):
first_half = the_string[0:int((x/2))] #create a list with part 1
second_half = the_string[(x-(int((x/2)))):x] #create a list with part 2
else: #if odd
for i in range(x):
first_half = the_string[:(int((x-1)/2))] #create a list with part 1 without the middle index
second_half = the_string[int(int(x-1)/2)+1:] #create a list with part 2 without the middle index
print(list(reversed(second_half)))
print(list(first_half))
if first_half == reversed(second_half): ##### NOT WORKING BUT DONT KNOW WHY #####
print("Yes")
else:
print("No")
Despite your comments first_half and second_half are substrings of your input, not lists. When you print them out, you're converting them to lists, but in the comparison, you do not convert first_half or reversed(second_half). Thus you are comparing a string to an iterator (returned by reversed), which will always be false.
So a basic fix is to do the conversion for the if, just like you did when printing the lists out:
if list(first_half) == list(reversed(second_half)):
A better fix might be to compare as strings, by making one of the slices use a step of -1, so you don't need to use reversed. Try second_half = the_string[-1:x//2:-1] (or similar, you probably need to tweak either the even or odd case by one). Or you could use the "alien smiley" slice to reverse the string after you slice it out of the input: second_half = second_half[::-1].
There are a few other oddities in your code, like your for i in range(x) loop that overwrites all of its results except the last one. Just use x - 1 in the slicing code and you don't need that loop at all. You're also calling int a lot more often than you need to (if you used // instead of /, you could get rid of literally all of the int calls).

how to best iterate through dictionary keys and compare the values?

I am very new to Programming and only started learning Python 3 about 2 wks ago.
Doing an exercise that I found rather difficult, that is designed to create a function that accepts a dictionary as an argument and is supposed to determine if the dictionary represents a "valid" chessboard. Plz note the following codes only address a single aspect of the function. The part I had the greatest struggle with.
I spent quite a bit of time working on this particular project and trying to insure that both options are "valid" code so afaik there are no errors in either?
Imagine a grid (I will print the list) that is supposed to represent the squares on a chessboard. Could someone tell me which code would be deemed as more acceptable? and Why? Or if there is a simpler way I could have done this? I will only post what I feel is "relevant" to my question if more is needed plz lmk.
checks that dictionary keys are valid Chessboard Squares
# acceptable range is columns 1 - 8 rows a - h
for board_squares in dic:
try: # this will accept any value as int
if (int(board_squares[0:-1]) <= 8 # as slice up to last key char
and board_squares[-1] <= 'h') \
is False:
print((Err) + ' Square outside range')
return False
except ValueError as e:
print((Err) + ' Improper dictionary')
return False # when testing function this can be replaced with return False
Important note: In this occurrence I am referring to "board_squares" as the dictionary keys. This is the first code I came up with after a lot of effort. It slices the dictionary key and compares it to what is supposed to be represent a "valid" chessboard square. I got a bit of negative feedback on it so I went back to the drawing board and came up with this code:
def char_range(c1, c2):
"""Generates the characters from `c1` to `c2`, inclusive."""
for c in range(ord(c1), ord(c2)+1):
yield chr(c)
chessboard_squares = []
for chr1 in range(1, 9):
for chr2 in char_range('a', 'h'):
chessboard_squares.append(str(chr1) + chr2)
print(chessboard_squares) # this is simply to print list so I have a visual representation
for key in dic:
if key in list \
is False:
print((Err) + ' Square outside range')
return False
Important note: In this occurrence I am referring to chessboard_squares as values in the list that the dictionary keys are compared to. This second code requires the function at the top to range over letters. I tried to insure it was very readable by using clearly defined variable labels. It creates a list of what the "valid dictionary keys should be" to represent Chessboard Squares. And lastly here is the printed list of what the valid dictionary keys "should be". Post is in the format of chessboard squares for clarity.
['1a', '1b', '1c', '1d', '1e', '1f', '1g', '1h',
'2a', '2b', '2c', '2d', '2e', '2f', '2g', '2h',
'3a', '3b', '3c', '3d', '3e', '3f', '3g', '3h',
'4a', '4b', '4c', '4d', '4e', '4f', '4g', '4h',
'5a', '5b', '5c', '5d', '5e', '5f', '5g', '5h',
'6a', '6b', '6c', '6d', '6e', '6f', '6g', '6h',
'7a', '7b', '7c', '7d', '7e', '7f', '7g', '7h',
'8a', '8b', '8c', '8d', '8e', '8f', '8g', '8h']
Since I posted this question I've learned a lot of new things and decided to answer my own question. Or if there is a simpler way I could have done this? Here is a much cleaner, and should be considered the "best", option.
try:
if all (
(1 <= int(row) <= 8) and ('a' <= col <= 'h')
for row, col in dict
):
return True
except ValueError:
return False
First we use the all() function that takes ALL the arguments passed to it and returns True if all are True. Empty strings count as a special exception of True.
All our dictionary keys are (supposed to be) 2 character strings which are in themselves iterable, and I can use multiple assignment(aka tuple unpacking) here if I assign exactly as many characters as are in the dictionary key to variables. In this case we assign the 1st char of the dictionary key to row and the 2nd char of the dictionary key to col(umn). I can still use try/except ValueError because if the dictionary key isn't exactly 2 characters it will raise the same error and I am checking for specific keys.
A simple understanding short version of a list or generator "comprehension" is doSomething for variable in iterable this is a "generator comprehension". What we end up with is:
Do something: cmp int(row) to 1 - 8 and col 'a' - 'h'
for: row(1st char of dict key), col(2nd char of dict key)
in: dictionary keys.
Because this is a "generator comprehension" it will create a set of values based off each loop iteration. and as an example might look something like this: True, False, False, True etc.
These values will in turn be passed to all() that will consume them and return True if ALL are True else False.
here are several resources to help understand the code should anyone wish to look further:
the all function:
https://docs.python.org/3/library/functions.html#all
understanding list comprehension:
https://medium.com/swlh/list-comprehensions-in-python-3-for-beginners-8c2b18966d93
this is great in that it explains "yield" which is vital in understanding generator comprehension:
What does the "yield" keyword do?
Multiple Assignment:
https://treyhunner.com/2018/03/tuple-unpacking-improves-python-code-readability/

Sorting algoritm

I want to make my algorithm more efficient via deleting the items it already sorted, but i don't know how I can do it efficiently. The only way I found was to rewrite the whole list.
l = [] #Here you put your list
sl = [] # this is to store the list when it is sorted
a = 0 # variable to store which numbers he already looked for
while True: # loop
if len(sl) == len(l): #if their size is matching it will stop
print(sl) # print the sorted list
break
a = a + 1
if a in l: # check if it is in list
sl.append(a) # add to sorted list
#here i want it to be deleted from the list.
The variable a is a little awkward. It starts at 0 and increments 1 by 1 until it matches elements from the list l
Imagine if l = [1000000, 1200000, -34]. Then your algorithm will first run for 1000000 iterations without doing anything, just incrementing a from 0 to 1000000. Then it will append 1000000 to sl. Then it will run again 200000 iterations without doing anything, just incrementing a from 1000000 to 1200000.
And then it will keep incrementing a looking for the number -34, which is below zero...
I understand the idea behind your variable a is to select the elements from l in order, starting from the smallest element. There is a function that does that: it's called min(). Try using that function to select the smallest element from l, and append that element to sl. Then delete this element from l; otherwise, the next call to min() will select the same element again instead of selecting the next smallest element.
Note that min() has a disadvantage: it returns the value of the smallest element, but not its position in the list. So it's not completely obvious how to delete the element from l after you've found it with min(). An alternative is to write your own function that returns both the element, and its position. You can do that with one loop: in the following piece of code, i refers to a position in the list (0 is the position of the first element, 1 the position of the second, etc) and a refers to the value of that element. I left blanks and you have to figure out how to select the position and value of the smallest element in the list.
....
for i, a in enumerate(l):
if ...:
...
...
If you managed to do all this, congratulations! You have implemented "selection sort". It's a well-known sorting algorithm. It is one of the simplest. There exist many other sorting algorithms.

Get the value of a list that produces the maximum value of a calculation

I apologize if this is a duplicate, I tried my best to find an existing question but was unsuccessful.
Recently, I've run into a couple of problems where I've needed to find the element in a list that produces the max/min value when a calculation is performed. For example, a list of real numbers where you want to find out which element produces the highest value when squared. The actual value of the squared number is unimportant, I just need the element(s) from the list that produces it.
I know I can solve the problem by finding the max, then making a pass through the list to find out which values' square matches the max I found:
l = [-0.25, 21.4, -7, 0.99, -21.4]
max_squared = max(i**2 for i in l)
result = [i for i in l if i**2 == max_squared]
but I feel like there should be a better way to do it. Is there a more concise/one-step solution to this?
This will return you just the element which gives the max when squared.
result = max(l, key = lambda k: k**2)
It does not get much better if you need the value in a list f.e. to see how often it occures. You can remeber the source element as well if you do not need that:
l = [-0.25, 21.4, -7, 0.99, -21.4]
max_squared = max( (i**2, i) for i in l) # remeber a tuple, with the result coming first
print(max_squared[1]) # print the source number (2nd element of the tuple)
Output:
21.4
Your calculation does only return the first occurence of abs(24.1) because max only returns one value, not two - if you need both, you still need to do:
print( [k for k in l if abs(k) == max_squared[1]])
to get
[21.4,-21.4]

choose one list. choose the one whose nth element is the smallest. Python 3

I have two lists. I have to choose one. I have to choose the one with the smallest nth element. So I can choose the smallest element easy with min, but how do I back track it to the list itself. Have literally no idea how to solve this presumably easy problem.
a = [2,45,1,56]
b= [0,23,3,87]
Which list has the smallest element at position 2? The answer here is list a.
In case I wasnt clear, the program sould be able to solve this task for any pair of lists.
Here is a very simple snippet that does what you want, but you might want to check for the size of the arrays, in case the index is out of range.
def choose_smallest(a, b, i):
if len(a) >= i or len(b) >= i:
return 0 # do whatever you want here
if a[i] < b[i]:
return a
else:
return b
Also notice that both nth elements in your array can have the exact same value... In this example array b will be returned, but you can change that behaviour if needed.
EDIT
Added array length check
According to your example, here is a sample code you can try. You can change the code as per your requirement.
a = [2,45,1,56]
b = [0,23,3,87]
n= int(input('Enter element number: ')) # n starts from zero to length of list - 1
if a[n] > b[n]:
print('List b has smaller nth element')
elif a[n] < b[n]:
print('List a has smaller nth element')
else:
print('Both lists have equal nth element')

Resources