0

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]
zelda26
  • 489
  • 2
  • 10
  • 33

4 Answers4

2

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]]
Austin
  • 25,759
  • 4
  • 25
  • 48
  • thank you! this is the answer: print (((arr%10 == 4) | (arr%10 == 9) & (arr >= 14) & (arr != 19)).astype(int)) – zelda26 Apr 25 '19 at 18:55
  • 1
    @C.Nivs, the requirement was a slightly unclear for me, thanks. By re-casting, do you mean converting to 1s and 0s? Those logical operations yield an array of trues and falses which are nothing but analogous to 1s and 0s. (To note that boolean is subclass of int.) – Austin Apr 25 '19 at 19:01
  • @Austin yeah, that was the question, but I found that in the docs shortly before you replied. Thanks, though! – C.Nivs Apr 25 '19 at 19:23
  • @Austin I ran some profiling against my code, and out of curiosity, profiled the `numpy` implementation as well, and wound up with numpy being slower than the `map` implementation. `python -m timeit -s 'import numpy as np; arr = np.array([[22, 13, 31, 13],[17, 14, 24, 22]])' '((arr >= 14) & (arr != 19) & ((arr%10 == 4) | (arr%10==9))).astype(int)' 100000 loops, best of 3: 6.53 usec per loop`. I can't quite wrap my head around that one, as I'd imagine `numpy` would blow the `map` implementation out of the water (this is python 3.6, numpy 1.16.2) – C.Nivs Apr 26 '19 at 15:24
1

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.Nivs
  • 12,353
  • 2
  • 19
  • 44
  • Thanks! This works: [[1 if x%10==4 or x%10==9 and x>=14 and x!=19 else 0 for x in sublist] for sublist in X] HOWEVER it doesn't pass because the solution doesn't compile fast enough...it has to be faster than a certain threshold – zelda26 Apr 25 '19 at 18:49
  • @JuliaDills Then I would definitely look at @Austin 's solution, as `numpy's` vectorized operations could potentially be much quicker – C.Nivs Apr 25 '19 at 18:51
0

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]]
andreihondrari
  • 5,743
  • 5
  • 30
  • 59
0

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.