Switching between min and max by user inter action - python

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.

Related

How to get particular index number of list items

my_list = ['A', 'B', 'C', 'D', 'E', 'B', 'F', 'D', 'C', 'B']
idx = my_list.index('B')
print("index :", idx)
In here I used the '.index()' function.
for i in my_list:
print(f"index no. {my_list.index(i)}")
I tried to find each index number of the items of the (my_list) list.
But it gave same result for same values. But they located in difference places of the list.
if 'B' == my_list[(len(my_list) - 1)]:
print("True")
if 'B' == my_list[(len(my_list) - 4)]:
print("True")
I need to mention particular values by the index number of their (to do something).
Imagine; I need to set values to nesting with the values of the list.
i.e :
my_list_2 = ['A', 'B', '2', 'C', '3', 'D', '4', 'E', 'B', '2', 'F', '6', 'D', 'C', '3', 'B']
- ------ ------ ------ - ------ ------ - ------ -
If I want to nesting values with their Consecutive (number type) items and
the other values need to nest with '*' mark (as default).Because they have no any Consecutive (numeric) values.
so then how I mention each (string) values and (numeric) values in a coding part to nesting them.
In this case as my example I expected result:
--> my_list_2 = [['A', ''], ['B', '2'], ['C', '3'], ['D', '4'], ['E', ''], ['B', '2'], ['F', '6'], ['D', ''], ['C', '3'], ['B', '']]
This is the coding part which I tried to do this :
def_setter = [
[my_list_2[i], '*'] if my_list_2[i].isalpha() and my_list_2[i + 1].isalpha() else [my_list_2[i], my_list_2[i + 1]]
for i in range(0, len(my_list_2) - 1)]
print("Result : ", def_setter)
But it not gave me the expected result.
Could you please help me to do this !
There might be a more pythonic way to reorganize this array, however, with the following function you can loop through the list and append [letter, value] if value is a number, append [letter, ''] if value is a letter.
def_setter = []
i = 0
while i < len(my_list_2):
if i + 1 == len(my_list_2):
if my_list_2[i].isalpha():
def_setter.append([my_list_2[i], ''])
break
prev, cur = my_list_2[i], my_list_2[i + 1]
if cur.isalpha():
def_setter.append([prev, ''])
i += 1
else:
def_setter.append([prev, cur])
i += 2
print(def_setter)
>>> [['A', ''],
['B', '2'],
['C', '3'],
['D', '4'],
['E', ''],
['B', '2'],
['F', '6'],
['D', ''],
['C', '3'],
['B', '']]

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']]

Find indexes of two lists

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))

Get a dict from a python list

I have a list my_list = ['a', 'b', 'c', 'd'] and I need to create a dictionary which looks like
{ 'a': ['a', 'b', 'c', 'd'],
'b': ['b', 'a', 'c', 'd'],
'c': ['c', 'a', 'b', 'd'],
'd': ['d', 'a', 'b', 'c'] }
each element as its value being the list but the first element is itself.
Here is my code
my_list = ['1', '2', '3', '4']
my_dict=dict()
for x in my_list:
n = my_lst[:]
n.remove(x)
n= [x] + n[:]
my_dict[x] = n
print my_dict
which gives
{'1': ['1', '2', '3', '4'],
'3': ['3', '1', '2', '4'],
'2': ['2', '1', '3', '4'],
'4': ['4', '1', '2', '3']}
as required.
But I don't think that's the most optimal way of doing it. Any help to optimize will be appreciated.
>>> seq
['a', 'b', 'c', 'd']
>>> {e: [e]+[i for i in seq if i != e] for e in seq}
{'a': ['a', 'b', 'c', 'd'],
'b': ['b', 'a', 'c', 'd'],
'c': ['c', 'a', 'b', 'd'],
'd': ['d', 'a', 'b', 'c']}
A faster approach (than the accepted answer) for larger lists is
{e: [e] + seq[:i] + seq[i+1:] for i, e in enumerate(seq)}
Relative timings:
In [1]: seq = list(range(1000))
In [2]: %timeit {e: [e]+[i for i in seq if i != e] for e in seq}
10 loops, best of 3: 40.8 ms per loop
In [3]: %timeit {e: [e] + seq[:i] + seq[i+1:] for i, e in enumerate(seq)}
100 loops, best of 3: 6.03 ms per loop
You can get hacky with a dictionary comprehension:
my_dict = {elem: list(sorted(my_list, key=lambda x: x != elem)) for elem in my_lst}
This works on the fact that the sorted function performs a stable sort, and False is less than True
Edit: This method is less clear and probably slower, use with caution.

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