Check nested list elementwise for multiple conditions and return 0 or 1 if condition is not met or is met.
I have to check
at least 14
cannot be equal to= 19
if the element ends in 4 or 9
For example, age array of
[[22, 13, 31, 13],
[17, 14, 24, 22]]
will have the output array as
[[0, 0, 0, 0],
[0, 1, 1, 0]]
I've tried flattening the list and then checking each condition, but it's not working.
flat_list = [item for sublist in age for item in sublist]
x=14
[not x for x in flat_list]
There's a faster numpy solution:
((arr >= 14) & (arr != 19) & ((arr%10 == 4) | (arr%10==9))).astype(int)
Code:
import numpy as np
arr = np.array([[22, 13, 31, 13],
[17, 14, 24, 22]])
print(((arr >= 14) & (arr != 19) & ((arr%10 == 4) | (arr%10==9))).astype(int))
# [[0 0 0 0]
# [0 1 1 0]]
You could do it with list comprehensions like so:
somelist = [[22, 13, 31, 13],
[17, 14, 24, 22]]
result = [[1 if (x%10==4 or x%10==9) and (x>=14 and x!=19) else 0 for x in sublist] for sublist in somelist]
result
[[0, 0, 0, 0], [0, 1, 1, 0]]
Where x%10 will get the last digit in each number, allowing the direct comparison. By grouping the two conditions, you can more logically lay out what you want to do, though this gets a bit messy for a list comprehension.
A better way (at the potential expense of speed) might be to use map:
def check_num(num):
value_check = num >= 14 and num != 19
last_num_check = num % 10 == 4 or num % 10 == 9
return int(value_check and last_num_check)
somelist = [[22, 13, 31, 13],
[17, 14, 24, 22]]
result = [[x for x in map(check_num, sublist)] for sublist in somelist]
result
[[0, 0, 0, 0], [0, 1, 1, 0]]
Timing the difference between operations:
List Comprehension
python -m timeit -s 'somelist = [[22, 13, 31, 13], [17, 14, 24, 22]]' '[[1 if (x%10==4 or x%10==9) and (x>=14 and x!=19) else 0 for x in sublist] for sublist in somelist]'
1000000 loops, best of 3: 1.35 usec per loop
Map
python -m timeit -s 'from somefunc import check_num; somelist = [[22, 13, 31, 13], [17, 14, 24, 22]]' '[[x for x in map(check_num, sublist)] for sublist in somelist]'
100000 loops, best of 3: 3.37 usec per loop
C.Nvis has a good answer with list comprehension. You can also solve this using nested for loops
def is_valid(x):
return (x == 14) or (x%10 == 4) or (x%10 == 9)
out = []
for sublist in matrix:
out_sublist = []
for i in sublist:
if (is_valid(i)):
out_sublist.append(1)
else:
out_sublist.append(0)
out.append(out_sublist)
print(out)
These answers are effectively the same algorithm.
Just for your example it can be done with a bit of mapping.
The way you can verify that the last digit equals to a number is by applying a modulo-10 on the number.
my_list = [[22, 13, 31, 13],[17, 14, 24, 22]]
result_list = []
for sublist in my_list:
result_list.append(list(map(lambda x: 1 if x % 10 == 4 and x >= 14 and x != 19 else 0, sublist)))
print(result_list)
will yield:
[[0, 0, 0, 0], [0, 1, 1, 0]]
Related
I want to just move the zero's to left and don't want to sort the list.
For example, if my list is like:
nums = [1, 10, 20, 0, 59, 63, 0, 8, 0]
Here's the output which I desire after moving all the Zero's to left:
output = [0, 0, 0, 1, 10, 20, 59, 63, 8]
Here's the code I tried:
class Solution:
def moveZeroes(self, nums):
c = 0
for i in range(len(nums)):
if nums[i] != 0:
nums[i], nums[c] = nums[c], nums[i]
c += 1
return nums
print(Solution().moveZeroes(nums))
This code gives me output as:
[1, 10, 20, 59, 63, 8, 0, 0, 0]
But my desired output is:
[0, 0, 0, 1, 10, 20, 59, 63, 8]
You can use sorted() with key as bool to achieve this as:
>>> nums = [1, 10, 20, 0, 59, 63, 0, 8, 0]
>>> sorted(nums, key=bool)
[0, 0, 0, 1, 10, 20, 59, 63, 8]
It will work for 0s. In order to make it more generic for any number, you can define key as lambda x: x!=left_num:
>>> left_num = 0
>>> sorted(nums, key=lambda x: x!=left_num)
[0, 0, 0, 1, 10, 20, 59, 63, 8]
As an alternative, here's a less Pythonic (but efficient) version of it using list.count():
>>> nums = [1, 10, 20, 0, 59, 63, 0, 8, 0]
>>> left_num = 0
>>> [left_num]*nums.count(left_num) + [n for n in nums if n!=left_num]
[0, 0, 0, 1, 10, 20, 59, 63, 8]
Here I am finding the count of zeroes in the list (say n), and assigning n zeroes in the start of new list. To get the rest of the unsorted list, I am using list comprehension to filter out the 0s from the list.
output = []
for i in nums:
if i == 0:
output.insert(0, 0)
else:
output.append(i)
output
sorted(nums, key=lambda i: i != 0)
# or
sorted(nums, key=bool)
you could filter out the zeros and insert the number of removed zeros at the begining of the output list:
nums = [1, 10, 20, 0, 59, 63, 0, 8, 0]
output = list(filter(None,nums))
output = [0]*(len(nums)-len(output)) + output
print(output)
# [0, 0, 0, 1, 10, 20, 59, 63, 8]
since the question does not mention any constraints, maybe this fine piece of one-line will help you:
def zero_left(list):
return [x for x in list if x == 0] + [x for x in list if x!=0]
I have a matrix (3x5) where a number is randomly selected in this matrix. I want to swap the selected number with the one down-right. I'm able to locate the index of the randomly selected number but not sure how to replace it with the one that is down then right. For example, given the matrix:
[[169 107 229 317 236]
[202 124 114 280 106]
[306 135 396 218 373]]
and the selected number is 280 (which is in position [1,3]), needs to be swapped with 373 on [2,4]. I'm having issues on how to move around with the index. I can hard-code it but it becomes a little more complex when the number to swap is randomly selected.
If the selected number is on [0,0], then hard-coded would look like:
selected_task = tard_generator1[0,0]
right_swap = tard_generator1[1,1]
tard_generator1[1,1] = selected_task
tard_generator1[0,0] = right_swap
Any suggestions are welcome!
How about something like
chosen = (1, 2)
right_down = chosen[0] + 1, chosen[1] + 1
matrix[chosen], matrix[right_down] = matrix[right_down], matrix[chosen]
will output:
>>> a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
>>> index = (1, 2)
>>> right_down = index[0] + 1, index[1] + 1
>>> a[index], a[right_down] = a[right_down], a[index]
>>> a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 13, 8, 9],
[10, 11, 12, 7, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
There should be a boundary check but its omitted
Try this:
import numpy as np
def swap_rdi(mat, index):
row, col = index
rows, cols = mat.shape
assert(row + 1 != rows and col + 1 != cols)
mat[row, col], mat[row+1, col+1] = mat[row+1, col+1], mat[row, col]
return
Example:
mat = np.matrix([[1,2,3], [4,5,6]])
print('Before:\n{}'.format(mat))
print('After:\n{}'.format(swap_rdi(mat, (0,1))))
Outputs:
Before:
[[1 2 3]
[4 5 6]]
After:
[[1 6 3]
[4 5 2]]
I have a 2D array of integer value:
[[26, 9, 24, 13],
[16, 14, 39, 29]]
I need to select the number >= 14, ends in 9 or 4, and not 39. It returns 1 if the criteria meets, otherwise return 0, i.e.
[[0, 0, 1,0],
[0,0,0,1]]
updated: code suggested by Tomothy32
result = result = [[int(x >= 14 and x % 10 in (4, 9) and x != 19) for x in sl] for sl in X]
another nested loop approach
def test(X):
out = [[0]*len(X[0]) for _ in range(len(X))]
for i in range(len(X)):
for j in range(len(X[i])):
check = X[i][j]
if check>=14 and check%5==4 and check!=39:
out[i][j] = 2
return out
You can use a list comprehension:
x = [[26, 9, 43, 13],
[16, 14, 39, 29]]
result = [[int(x >= 14 and x % 10 == 9 and x != 39) for x in sl] for sl in x]
print(result)
# [[0, 0, 0, 0], [0, 0, 0, 1]]
To get the last digit, use the remainder/modulo operator.
Change this statements:
if element >=14 and element !=39:
to
if element >=14 and element !=39 and element%10==9:
Takes a list of numbers and groups the numbers by their tens place, giving every tens place it's own sublist.
ex:
$ group_by_10s([1, 10, 15, 20])
[[1], [10, 15], [20]]
$ group_by_10s([8, 12, 3, 17, 19, 24, 35, 50])
[[3, 8], [12, 17, 19], [24], [35], [], [50]]
my approach:
limiting = 10
ex_limiting = 0
result = []
for num in lst:
row = []
for num in lst:
if num >= ex_limiting and num <= limiting:
row.append(num)
lst.remove(num)
result.append(row)
ex_limiting = limiting
limiting += 10
But it returns [[1], [10, 20]].
What's wrong with my approach and how can I fix it?
You may already have a correct answer, but here's an alternative solution:
def group_by_10s(mylist):
result = []
decade = -1
for i in sorted(mylist):
while i // 10 != decade:
result.append([])
decade += 1
result[-1].append(i)
return result
group_by_10s([8, 12, 3, 17, 19, 24, 35, 50])
#[[3, 8], [12, 17, 19], [24], [35], [], [50]]
It uses only plain Python, no extra modules.
You can use a list comprehension:
def group_by_10s(_d):
d = sorted(_d)
return [[c for c in d if c//10 == i] for i in range(min(_d)//10, (max(_d)//10)+1)]
print(group_by_10s([1, 10, 15, 20]))
print(group_by_10s([8, 12, 3, 17, 19, 24, 35, 50]))
print(group_by_10s(list(range(20))))
Output:
[[1], [10, 15], [20]]
[[3, 8], [12, 17, 19], [24], [35], [], [50]]
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]
Credit to advice for not iterating list during loop.
I got this answer at the end, for anyone who wants the answer.
Thanks for support!
def group_by_10s(numbers):
external_loop = int(max(numbers)/10)
limiting = 10
ex_limiting = 0
result = []
for external_loop_count in range(external_loop+1):
row = []
for num in numbers:
if num >= ex_limiting and num < limiting:
row.append(num)
row.sort()
result.append(row)
ex_limiting = limiting
limiting += 10
return(result)
How about this one?
numbers = [8, 12, 3, 17, 19, 24, 35, 50]
def group_by_10s(numbers):
arr = []
for i in range((max(numbers) / 10) + 1):
arr.append([])
numbers.sort()
for number in numbers:
if number < 10:
arr[0].append(number)
else:
index = number / 10
arr[index].append(number)
return arr
print group_by_10s(numbers)
# [[3, 8], [12, 17, 19], [24], [35], [], [50]]
Do not modify the list while you are iterating over it, as when you remove items from it, some items get skipped over. Also change the bounds so that you will only append to row if num < limiting. I would add in a check to make sure the list has elements before adding it to result:
for num in lst:
row = []
for num in lst:
if num >= ex_limiting and num < limiting:
row.append(num)
if len(row) > 0 :
result.append(row)
ex_limiting = limiting
limiting += 10
This will yield:
[[1], [10, 15], [20]]
I have this situation:
main_list = [12, 10, 30, 10, 11,10, 31]
get_indices = [1, 0, 1, 1, 0, 0, 0]
What I want to do is, extract elements from main_list according to the boolean value in get_indices.
I tried the following but it is not working :
result = main_list[bool(get_indices)]
print result
10
It should be 12, 30, 10
I just came across compress() which is best suited for this task.
compress() generates an iterator for efficient looping.
from itertools import compress
main_list = [12, 10, 30, 10, 11,10, 31]
get_indices = [1, 0, 1, 1, 0, 0, 0]
print list(compress(main_list, get_indices))
[12, 30, 10]
You can use list comprehension -
result = [x for i, x in enumerate(main_list) if get_indices[i]]
You do not need to use bool() , 0 is considered False-like in boolean context, and anything non-zero is True-like.
Example/Demo -
>>> main_list = [12, 10, 30, 10, 11,10, 31]
>>> get_indices = [1, 0, 1, 1, 0, 0, 0]
>>> result = [x for i, x in enumerate(main_list) if get_indices[i]]
>>> result
[12, 30, 10]
Or if you really want something similar to your method, since you say -
But if I was able to get my method working, I could also do for example : result = main_list[~bool(get_indices)] to get : [10, 11, 10, 31]
You can use numpy , convert the lists to numpy arrays. Example -
In [30]: import numpy as np
In [31]: main_list = [12, 10, 30, 10, 11,10, 31]
In [32]: get_indices = [1, 0, 1, 1, 0, 0, 0]
In [33]: main_array = np.array(main_list)
In [34]: get_ind_array = np.array(get_indices).astype(bool)
In [35]: main_array[get_ind_array]
Out[35]: array([12, 30, 10])
In [36]: main_array[~get_ind_array]
Out[36]: array([10, 11, 10, 31])