Find indexes of two lists - python

I have two numpy lists:
x = ['A', 'A', 'C', 'A', 'V', 'A', 'B', 'A', 'A', 'A']
y = ['1', '2', '1', '1', '3', '2', '1', '1', '1', '1']
How can I find indexes when simulataneously x equals 'A' and y equals '2'?
I expect to get indexes [1, 5].
I tried to use:
np.where(x == 'A' and y == '2') but it didn't help me.

pure python solution:
>>> [i for i,j in enumerate(zip(x,y)) if j==('A','2')]
[1, 5]

You need to convert the list to numpy array in order to use vectorized operation such as == and &:
import numpy as np
np.where((np.array(x) == "A") & (np.array(y) == "2"))
# (array([1, 5]),)
Shorter version (if you are sure that x and y are numpy arrays):
>>> np.where(np.logical_and(x == 'A', y == '2'))
(array([1, 5]),)

If you want to work with lists:
idx1 = [i for i, x in enumerate(x) if x == 'A']
idx2 = [i for i, x in enumerate(y) if x == '2']
list(set(idx1).intersection(idx2))

Related

Take integer only from a nested list and apply function to it

I am super new at Python and I am facing a problem when converting a nested list to a list of integer only.
I have this type of nested list in which all sub-list contains strings (digit and char)
lists = [['1', '2', '0', 'a', 'b'], ['3', '2', '1'], ['1','5', '5']]
I want to convert the digits to integer, and also put the char in one list. The output that I want is something like this
`new_lists = [[1, 2, 0, 'a', 'b'], [3, 2, 1], [1, 5, 5]]`
What would i do is something like this
for item in lists:
new_list=[]
if (in the first list item can be converted to integer):
new_list.append(int(item))
else:
new_list.append(item)
How the string can be converted to an integer? Or is there any better way to do it?
Thanks in advance
Define a function that will convert a string to an int when it can, and use it in a nested list comprehension:
def safe_int(s):
try:
return int(s)
except ValueError:
return s
lists = [['1', '2', '0', 'a', 'b'], ['3', '2', '1'], ['1', '5', '5']]
new_lists = [[safe_int(i) for i in sub_list] for sub_list in lists]
The value of new_lists will be:
[[1, 2, 0, 'a', 'b'], [3, 2, 1], [1, 5, 5]]
using str.isdigit() you can check whether a string is integer for not.
lists2 = list(map(lambda y:[int(x) if x.isdigit() else x for x in y], lists))
or
list2 = []
for i in lists:
tmp = []
for j in i:
try:
val = int(j)
except ValueError:
val = j
tmp.append(val)
list2.append(tmp)

Switching between min and max by user inter action

I have the following code which allows the user to choose between min and max filtering. However, min works on element 1 but max works on element 2. Is there a better way to implement it?
from operator import itemgetter
data = [['A', '2', '4'], ['B', '2', '12'],
['C', '3', '88'], ['D', '4', '88']]
fn_max = False
if fn_max is True:
mx = max(data, key=itemgetter(2))[2]
mx_values = [d for d in data if d[2] == mx]
else:
mx = min(data, key=itemgetter(1))[1]
mx_values = [d for d in data if d[1] == mx]
print(mx_values)
You can put them into a function:
from operator import itemgetter
data = [['A', '2', '4'], ['B', '2', '12'],
['C', '3', '88'], ['D', '4', '88']]
def my_func(fn_max):
func, i = (max, 2) if fn_max else (min, 1)
mx = func(data, key=itemgetter(i))[i]
return [d for d in data if d[i] == mx]
fn_max = False
print(my_func(fn_max))
Output:
[['A', '2', '4'], ['B', '2', '12']]
This is arguably better (although it's unclear what you need it for, so it's hard to say if it would really be better):
data = [
['A', 2, 4],
['B', 2, 12],
['C', 3, 88],
['D', 4, 88]
]
def fn_filter(fn, column, data):
value = fn(rec[column] for rec in data)
return list(filter(lambda rec: rec[column] == value, data))
print(fn_filter(min, 1, data))
print(fn_filter(max, 2, data))
Result:
[['A', 2, 4], ['B', 2, 12]]
[['C', 3, 88], ['D', 4, 88]]
fn_filter allows you to apply any function fn to a specific column column of the dataset data and will return a list of all the records in data that have that same value in that same column.

Split a list into sublists based on a set of indexes in Python

I have a list similar to below
['a','b','c','d','e','f','g','h','i','j']
and I would like to separate by a list of index
[1,4]
In this case, it will be
[['a'],['b','c'],['d','e','f','g','h','i','j']]
As
[:1] =['a']
[1:4] = ['b','c']
[4:] = ['d','e','f','g','h','i','j']
Case 2: if the list of index is
[0,6]
It will be
[[],['a','b','c','d','e'],['f','g','h','i','j']]
As
[:0] = []
[0:6] = ['a','b','c','d','e']
[6:] = ['f','g','h','i','j']
Case 3 if the index is
[2,5,7]
it will be
[['a','b'],['c','d','e'],['h','i','j']]
As
[:2] =['a','b']
[2:5] = ['c','d','e']
[5:7] = ['f','g']
[7:] = ['h','i','j']
Something along these lines:
mylist = ['a','b','c','d','e','f','g','h','i','j']
myindex = [1,4]
[mylist[s:e] for s, e in zip([0]+myindex, myindex+[None])]
Output
[['a'], ['b', 'c', 'd'], ['e', 'f', 'g', 'h', 'i', 'j']]
This solution is using numpy:
import numpy as np
def do_split(lst, slices):
return [sl.tolist()for sl in np.split(lst, slices)]
splits = do_split(a, [2,5,7])
Out[49]:
[['a', 'b'], ['c', 'd', 'e'], ['f', 'g'], ['h', 'i', 'j']]
a = [1,2,3,4,5,6,7,8,9,10]
newlist = []
divide = [2,5,7]
divide = [0]+divide+[len(a)]
for i in range(1,len(divide)):
newlist.append(a[divide[i-1]:divide[i]])
print(newlist)
Output:
[[1, 2], [3, 4, 5], [6, 7], [8,9,10]]
I wrote this function to do what you're asking
def splitter(_list, *args):
args_list = [0]
args_list += args
args_list.append(len(_list))
new_list = []
for i, arg in enumerate(args_list):
try:
new_list.append(_list[arg:args_list[i+1]])
except IndexError:
continue
return new_list
The function can be used like this:
mylist = ['1', '2', '3', '4', '5', '6']
splitter(mylist, 2, 4)
Which returns:
[['1', '2'], ['3', '4'], ['5', '6']]

Concatenate two lists using condition

I need to concatenate lists A and B using condition that two lists transform to list C, with the same length, but each i element doesn't change position and list is sorted. Else return empty list:
A = ['a', 'b', 'c']
B = ['x', 'y', 'z']
concatenated to: C = ['a', 'b', 'z'].
or
A = ['8', '2', '3']
B = ['1', '2', '0']
concatenated to: C = ['1', '2', '3'].
I absolutely have no idea how I can start solve my problem. Which algorithm I have to use?
UPD:
Another examples:
A = ['a', 'b', 'c']
B = ['x', 'x', 'x']
result is: ['a', 'b', 'x']
A = ['b', 'a']
B = ['x', 'c']
result must be: ['b', 'c'].
And result of concatenation of these two lists is an empty list:
A = ['e','a'],
B = ['f','b']
Do you just need to switch the last two elements in each list? If so, this is a simple way that lets you see what is going on.
lst1 = ['a', 'b', 'c']
lst2 = ['x', 'x', 'x']
lst3 = lst1
lst3[len(lst2)-1] = lst2[len(lst2)-1]
lst3
Out: ['a', 'b', 'x']
Else, explain the logic behind what you are trying to do a little more.
This can be done with a greedy algorithm, iterate over both list and take the minimum value that is greater from the previous item you had taken.
prev = None
A = ['a', 'b', 'c']
B = ['x', 'x', 'x']
n = len(A)
result = []
for i in range(n):
mn, mx = A[i],B[i]
if mx<mn:
mn,mx = mx,mn
if prev == None or mn >= prev:
prev = mn
result.append(prev)
elif mx >= prev:
prev = mx
result.append(prev)
else:
print "can't be done"
break
if len(result) == n:
print result

Taking elements two by two from lists

I have lists like:
['a', '2', 'b', '1', 'c', '4']
['d', '5', 'e', '7', 'f', '4', 'g', '6']
And I want to make a dictionary consist of keys as letters and values as numbers. I mean:
{'a': 2, 'b': 1, 'c': 4, 'd':5, 'e':7, 'f':4, 'g':6}
You can try:
>>> l = ['a', '2', 'b', '1', 'c', '4']
>>> it = iter(l)
>>> dict(zip(it, it))
{'a': '2', 'c': '4', 'b': '1'}
First you create an iterator out of the list. Then with zip of the iterator with itself you take pair of values from the list. Finally, with dict you transform these tuples to your wanted dictionary.
If you also want to do the string to number conversion, then use:
{x: int(y) for x, y in zip(it, it)}
EDIT
If you don't want to use zip then:
{x: int(next(it)) for x in it}
l = ['a', '2', 'b', '1', 'c', '4']
d = {k:v for k,v in zip(l[::2], l[1::2])}
Or if you want the numbers to be actual numbers:
l = ['a', '2', 'b', '1', 'c', '4']
d = {k:int(v) for k,v in zip(l[::2], l[1::2])}
Use float(v) instead of int(v) if the numbers have the potential to be floating-point values instead of whole numbers.
Without using any built-in functions:
l = ['a', '2', 'b', '1', 'c', '4']
d = {}
l1 = l[::2]
l2 = l[1::2]
idx = 0
while 1:
try:
d[l1[idx]] = l2[idx]
idx += 1
except IndexError:
break
You can split the lists into two, one containing the letters and the other containing the keys, with
key_list = old_list[::2]
value_list = old_list[1::2]
Then you can loop over the two lists at once with zip and you can make the dictionary.

Categories

Resources