How i can replace None value in list with int? - python

enter code hereSo, Basically I have a list with int values, and I want to see which values are missing in List. To do that I am comparing Value with a range from 1 to 9 (range(1,9)).
matrix = [None, 8, 3, 9, 2, 1, 6, 5, None]
when i run this code:
for row in matrix:
if range(1,9) not in row :
print(row)
else:
print('wrong logic')
I am getting this error
TypeError: 'NoneType' object cannot be interpreted as an integer

We can see this as a difference of two sets, one with all numbers of interest and one with the numbers in your list. All you need to do is to subtract the set with all numbers by the set with the values in your list.
list = [None, 8, 3, 9, 2, 1, 6, 5, None]
missing_numbers = set(range(1,9)) - set(list)
print(missing_numbers)
This will print {4, 7}.

Remove the Nones from the list before evaluating whether the range is in the list.
start_list = [None, 8, 3, 9, 2, 1, 6, 5, None]
new_list = [item for item in start_list if item is not None]
And then check for numbers 1-9 in the new list.
Another way to do this without even removing the Nones is to just loop through the numbers 1-9 and check if they are in the list.
start_list = [None, 8, 3, 9, 2, 1, 6, 5, None]
missing = []
for num in range(1,10):
if num not in start_list:
missing.append(num)
print(missing)

the range function takes integers as its arguments. you cannot pass it a None value. You can convert your None values to zero's first.
my_list = [None, 8, 3, 9, 2, 1, 6, 5, None]
my_list = [item if item else 0 for item in my_list]
print(my_list)
OUTPUT
[0, 8, 3, 9, 2, 1, 6, 5, 0]

Requirement is not very clear but I suppose you want to compare values to list and finally print the missing numbers.
A possible approach to obtain the missing values in list_to_check is to compare if its entries are present in good_values and, if so, remove them from good_values.
What will be left is just the missing entries in list_to_check.
list_to_check = [None, 8, 3, 9, 2, 1, 6, 5, None]
good_values = list(range(1, len(list_to_check) + 1))
for number in list_to_check:
if number in good_values:
good_values.remove(number)
print(good_values)
Output
[4, 7]
Edit
Now I read from comments that you would also like to add the missing numbers in place of the None items.
Here's a more verbose and easy to understand solution:
list_to_check = [None, 8, 3, 9, 2, 1, 6, 5, None]
good_values = list(range(1, len(list_to_check) + 1))
for number in list_to_check:
if number in good_values:
good_values.remove(number)
result = []
for value in list_to_check:
if value is None:
result.append(good_values.pop())
else:
result.append(value)
print(result)
Output:
[7, 8, 3, 9, 2, 1, 6, 5, 4]
For reasons that I do not fully understand if you are not using list comprehensions in your Python code you are simply not cool.
Let's also be cool, then!
Here's a shorter solution for the same problem:
list_to_check = [None, 8, 3, 9, 2, 1, 6, 5, None]
good_values = list(range(1, len(list_to_check) + 1))
for number in list_to_check:
if number in good_values:
good_values.remove(number)
print([good_values.pop() if value is None else value for value in list_to_check])
Output
[7, 8, 3, 9, 2, 1, 6, 5, 4]

Related

Python - How to find the longest sequence in a integer list of neighbor numbers

How I find the longest sub-list in list of number pairs that has the difference of 1.
So "number neighbors" could be element 1 and 2 or element 7 and 6.
If the list is [7, 1, 2, 5, 7, 6, 5, 6, 3, 4, 2, 1, 0],
Then the desired output should be 4. The sub-list would be then [7, 6, 5, 6].
This is what I have for now. The for loop formula is really broken and I don't know how to solve this.
list = [7, 1, 2, 5, 7, 6, 5, 6, 3, 4, 2, 1, 0]
sublist = []
for i in list:
if list[i] - list[i+1] == 1 or list[i] - list[i+1] == -1:
sublist.append(i)
print(sublist)
print(len(sublist))
more-itertools makes it simple:
from more_itertools import split_when
lst = [7, 1, 2, 5, 7, 6, 5, 6, 3, 4, 2, 1, 0]
print(max(split_when(lst, lambda x, y: abs(x - y) != 1), key=len))
Its best to break these types of problems up into their parts
the main problem here is to get all sequential sequences
def get_sequences_iter(an_array):
# start a new sequence with first value (or empty)
sequence = an_array[:1]
# check each index with the value that comes before
for idx in range(1,len(an_array)):
if an_array[idx] - an_array[idx-1] in {1,-1}:
# this is part of a run append it
sequence.append(an_array[idx])
else:
# run is broken
yield sequence
# start a new run
sequence = [an_array[idx]]
#capture final sequence
yield sequence
once you have this you can get all the runs in a list in O(n) time
sequences = get_sequences_iter([7, 1, 2, 5, 7, 6, 5, 6, 3, 4, 2, 1, 0])
for sequence in sequences:
print(sequence)
hopefully with this information you can figure out how to solve your actual question
but just in case
print(max(sequences,key=len))

Sum of every element in a list

So i have a list:
list1 = [[1, 3, 6, 8, 9, 9, 12], [1, 2, 3, 2, 1, 0, 3, 3]]
but you can also split it into two lists, if it make it any easier. All i have to do is sum every digit with every other digit. Like you know
first row:
1+1, 1+2, 1+3, 1+2, 1+1...
second:
3+1... etc.
first = [1, 3, 6, 8, 9, 9, 12]
second = [1, 2, 3, 2, 1, 0, 3, 3]
w = [x + y for x, y in zip(first, second)]
I was trying to do it in this way. But it doesn't work*, any ideas?
*i mean its summing in a wrong way, instead of every possible digits with every possible, just the first one in 1st list with 1st in second list.
zip is getting only pairs that sit at the same index. You should instead have a double loop:
[x + y for x in first for y in second]
You can do it using itertools to get all possible pair then make a pair of sum list
import itertools
first = [1, 3, 6, 8, 9, 9, 12]
second = [1, 2, 3, 2, 1, 0, 3, 3]
res = itertools.product(first, second)
ress = [sum(pair) for pair in res]
print(ress)

How do I get the index of the common integer element from two separate lists and plug it to another list?

I have 3 lists.
A_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Q_act = [2, 3]
dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
All lists are integers.
What I am trying to do is to compare Q_act with A_set then obtain the indices of the numbers that match from A_set.
(Example:
Q_act has the elements [2,3]
it is located in indices [1,2] from A_set)
Afterwards, I will use those indices to obtain the corresponding value in dur and store this in a list called p_dur_Q_act.
(Example: using the result from the previous example, [1,2]
The values in the dur list corresponding to the indices [1,2] should be stored in another list called p_dur_Q_act
i.e. [4,5] should be the values stored in the list p_dur_Q_act)
So, how do I get the index of the common integer element (which is [1,2]) from two separate lists and plug it to another list?
So far here are the code(s) I used:
This one, I wrote because it returns the index. But not [4,5].
p_Q = set(Q_act).intersection(A_set)
p_dur_Q_act = [i + 1 for i, x in enumerate(p_Q)]
print(p_dur_Q_act)
I also tried this but I receive an error TypeError: argument of type 'int' is not iterable
p_dur_Q_act = [i + 1 for i, x in enumerate(Q_act) if any(elem in x for elem in A_set)]
print(p_dur_Q_act)
Another option is to use the enumerate iterator to generate every index, and then select only the ones you want:
a_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
q_act = [2, 3]
dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
p_dur_q_act = [i for i,v in enumerate(a_set) if v in q_act]
print([dur[p] for p in p_dur_q_act if p in dur]) # [4, 5]
This is more efficient than repeatedly calling index if the number of matches is large, because the number of calls is proportional to the number of matches, but the duration of calls is proportional to the length of a_set. The enumerate approach can be made even more efficient by turning q_act into a set, since in scales better with sets than lists. At these scales, though, there will be no observable difference.
You don't need to map these to index values, though. You can get the same result if you use zip to map a_set to dur and then select the d values whose a values are in q_act.
a_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
q_act = {2, 3}
dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
p_dur_q_act = [d for a, d in zip(a_set, dur) if a in q_act]
Use index function to get the index of the element in the list.
>>> a_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> q_act = [2, 3]
>>> dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
>>>
>>> print([dur[a_set.index(q)] for q in set(a_set).intersection(q_act)])
[4, 5]

Python move all elements of a list one position back with same len

def list_move_back(new_value, value_list):
for i in reversed(value_list):
if value_list.index(i) != len(value_list)-1:
value_list[value_list.index(i)+1] = i
value_list[0] = new_value
return value_list
I want to get the following result:
list_example = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
list_example = list_move_back(12, list_example]
print(list_example)
>>>[12, 1, 2, 3, 4, 5, 6, 7, 8, 9]
It works if I run the function two times:
list_example = list_move_back(12, list_example]
print(list_example)
>>>[12, 12, 1, 2, 3, 4, 5, 6, 7, 8]
but if I want to run it a third time, the result looks like that:
list_example = list_move_back(12, list_example]
print(list_example)
>>>[12, 12, 1, 1, 3, 4, 5, 6, 7, 8]
The first 1 should be a 12. I have no idea why it doesn't work.
Just use list slicing:
def list_move_back(new_value, list_of_values):
return [new_value] + list_of_values[:-1]
Explanation: list_of_values[:-1] returns all the elements except for the last. By appending it to the new value, you get the wanted result. This answer has a pretty cool explanation of how list slicing works.
Also, if for some reason you'd like the "verbose" way to do this (maybe for an exercise or whatever), here's a way to go about it:
def list_move_back(new_value, list_of_values):
for i in range(len(list_of_values)-1, 0, -1):
list_of_values[i] = list_of_values[i-1]
list_of_values[0] = new_value
return list_of_values
I'd recommend list slicing over this method 9/10 times but again, I'm just leaving this here because there might be a case where someone wants to do this as some sort of mental exercise for indexing.
If you need the list to change in place, you can use the list methods .pop() to remove the last item and .insert(0,value) to add an item to the front:
>>> L = list(range(1,11))
>>> L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> id(L)
1772071032392
>>> L.pop();L.insert(0,12)
10
>>> L
[12, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> id(L) # same list id, modified in place...
1772071032392

Is it possible to sort a list with reduce?

I was given this as an exercise. I could of course sort a list by using sorted() or other ways from Python Standard Library, but I can't in this case. I think I'm only supposed to use reduce().
from functools import reduce
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
sorted_arr = reduce(lambda a,b : (b,a) if a > b else (a,b), arr)
The error I get:
TypeError: '>' not supported between instances of 'tuple' and 'int'
Which is expected, because my reduce function inserts a tuple into the int array, instead of 2 separate integers. And then the tuple gets compared to an int...
Is there a way to insert back 2 numbers into the list, and only run the function on every second number in the list? Or a way to swap the numbers with using reduce()?
Documentation says very little about the reduce function, so I am out of ideas right now.
https://docs.python.org/3/library/functools.html?highlight=reduce#functools.reduce
Here is one way to sort the list using reduce:
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
sorted_arr = reduce(
lambda a, b: [x for x in a if x <= b] + [b] + [x for x in a if x > b],
arr,
[]
)
print(sorted_arr)
#[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
At each reduce step, build a new output list which concatenates a list of all of the values less than or equal to b, [b], and a list of all of the values greater than b. Use the optional third argument to reduce to initialize the output to an empty list.
I think you're misunderstanding how reduce works here. Reduce is synonymous to right-fold in some other languages (e.g. Haskell). The first argument expects a function which takes two parameters: an accumulator and an element to accumulate.
Let's hack into it:
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
reduce(lambda xs, x: [print(xs, x), xs+[x]][1], arr, [])
Here, xs is the accumulator and x is the element to accumulate. Don't worry too much about [print(xs, x), xs+[x]][1] – it's just there to print intermediate values of xs and x. Without the printing, we could simplify the lambda to lambda xs, x: xs + [x], which just appends to the list.
The above outputs:
[] 17
[17] 2
[17, 2] 3
[17, 2, 3] 6
[17, 2, 3, 6] 1
[17, 2, 3, 6, 1] 3
[17, 2, 3, 6, 1, 3] 1
[17, 2, 3, 6, 1, 3, 1] 9
[17, 2, 3, 6, 1, 3, 1, 9] 5
[17, 2, 3, 6, 1, 3, 1, 9, 5] 3
As we can see, reduce passes an accumulated list as the first argument and a new element as the second argument.(If reduce is still boggling you, How does reduce work? contains some nice explanations.)
Our particular lambda inserts a new element into the accumulator on each "iteration". This hints at insertion sort:
def insert(xs, n):
"""
Finds first element in `xs` greater than `n` and returns an inserted element.
`xs` is assumed to be a sorted list.
"""
for i, x in enumerate(xs):
if x > n:
return xs[:i] + [n] + xs[i:]
return xs + [n]
sorted_arr = reduce(insert, arr, [])
print(sorted_arr)
This prints the correctly sorted array:
[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
Note that a third parameter to reduce (i.e. []) was specified as we initialise the sort should with an empty list.
Ninjad! But yes, it's an insertion sort.
def insert(acc, e):
for i, x in enumerate(acc):
if x > e:
acc.insert(i, e)
return acc
acc.append(e)
return acc
reduce(insert, [1, 2, 6, 4, 7, 3, 0, -1], [])
outputs
[-1, 0, 1, 2, 3, 4, 6, 7]
After some thinking I concluded that it is also possible to do swap-based sort, if you are allowed to use reduce more than once. Namely:
from functools import reduce
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
def func(acc,x):
if not acc:
return [x]
if acc[-1]<x:
return acc+[x]
else:
return acc[:-1]+[x]+acc[-1:]
def my_sort(x):
moresorted = reduce(func,x,[])
print(moresorted)
if x==moresorted:
return moresorted
else:
return my_sort(moresorted)
print('arr:',arr)
arr_sorted = my_sort(arr)
print('arr sorted:',arr_sorted)
Output:
arr: [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
[2, 3, 6, 1, 3, 1, 9, 5, 3, 17]
[2, 3, 1, 3, 1, 6, 5, 3, 9, 17]
[2, 1, 3, 1, 3, 5, 3, 6, 9, 17]
[1, 2, 1, 3, 3, 3, 5, 6, 9, 17]
[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
arr sorted: [1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
I placed print(moresorted) inside func for educational purposes, you could remove it if you wish.
Now explanation: my_sort is recursive function, with every run of it list become more and more sorted. func which is used as function in reduce does append new element and then swaps 2 last elements of list if they are not in ascending order.
This mean in every run of my_sort number "travels" rightward until in take place where next number is bigger.
if not acc is required for starting - notice that third argument of reduce is [] meaning that during first execution of func in each reduce first argument for func is [], so asking acc[-1]<x? would result in error.
Let's understand this
(1)Usage of Reduce is basically to reduce the expression to a single final value
(2)reduce() stores the intermediate result and only returns the final summation value
(3)We will take the smallest element using reduce, append it to sorted_list and remove from the original list
(4)Now the reduce will work on the rest of the elements and repeat step 3 again
(5)while list_nums: will run until the list becomes empty
list_of_nums = [1,19,5,17,9]
sorted_list=[]
while list_of_nums:
maxvalue=reduce(lambda x,y: x if x<y else y,list_of_nums)
sorted_list.append(maxvalue)
list_of_nums.remove(maxvalue)
print(sorted_list)
[1, 5, 9, 17, 19]

Categories