Как получить ближайшее значение в списке?

#python #list #math

#python #Список #математика

Вопрос:

У меня есть переменная, которая выглядит следующим образом: my_value = 188 и у меня есть список, который выглядит следующим образом:

 my_list = [
    ['Morocco', 'Meat', '190,00', '0,15'], 
    ['Morocco', 'Meat', '189,90', '0,32'], 
    ['Morocco', 'Meat', '189,38', '0,44'],
    ['Morocco', 'Meat', '188,94', '0,60'],
    ['Morocco', 'Meat', '188,49', '0,78'],
    ['Morocco', 'Meat', '187,99', '0,101'],
    ['Spain', 'Meat', '190,76', '0,10'], 
    ['Spain', 'Meat', '190,16', '0,20'], 
    ['Spain', 'Meat', '189,56', '0,35'],
    ['Spain', 'Meat', '189,01', '0,40'],
    ['Spain', 'Meat', '188,13', '0,75'],
    ['Spain', 'Meat', '187,95', '0,85'],
    ['Italy', 'Meat', '190,20', '0,11'],
    ['Italy', 'Meat', '190,10', '0,31'], 
    ['Italy', 'Meat', '189,32', '0,45'],
    ['Italy', 'Meat', '188,61', '0,67'],
    ['Italy', 'Meat', '188,01', '0,72'],
    ['Italy', 'Meat', '187,36', '0,80']]
 

Как вы можете видеть, my_list числа в индексе [2] убывают, а числа в индексе [3] возрастают. Теперь для каждого списка я хочу проверить, по какому индексу [3] индекс [2] является самым близким my_value , НО он не должен опускаться ниже my_value.

Я попробовал приведенный ниже код:

 for key,sublists in itertools.groupby(my_list,lambda y:y[0]):
        v=[] #initialize it in case no element fulfill the condition
        for v in itertools.takewhile(lambda x:float(x[-1].replace(",","."))<my_value ,sublists):
            pass
        if v: 
            print(v[-1])
 

Я получил следующий вывод:

 0,101
0,85
0,80
 

Результат, который я хочу, это:

 0,78
0,75
0,72
 

Комментарии:

1. Что вы подразумеваете под «превзойти ваше значение»? В вашем примере желаемого результата все значения с индексом 2 больше 188 и, следовательно, превышают ваше значение. Вы имеете в виду, что они не должны опускаться ниже вашего значения?

2. @sunnytown с превышением, я имею в виду <188 . Все наоборот. Я должен изменить свой словарь. Вместо того, чтобы превосходить, я имею в виду «падение ниже». Вы понимаете?

3. Да, я просто хотел уточнить, действительно ли это то, что вы имеете в виду.

Ответ №1:

Это та работа, в которой pandas приходит на помощь:

 import pandas as pd
my_value = 188
my_list = [] # complete this with your list above

df = pd.DataFrame(my_list) # make a DataFrame out of your list
df[2] = df[2].str.replace(",", ".").astype(float) # convert those strings to actual floats
df[3] = df[3].str.replace(",", ".").astype(float)
selected = df[df[2]>my_value].groupby(by=0).agg({2:'min',3:'last'}) # selects what you want

print(list(selected[3])) # if you just want those values
 

выведет

[0.72, 0.78, 0.75]

selected будет выглядеть так:

 0       2       3
Italy   188.01  0.72
Morocco 188.49  0.78
Spain   188.13  0.75
 

Ответ №2:

 my_value = 188
numbers = [float(line[2].replace(',', '.')) for line in my_list]
minima = [(num - my_value, line[3]) for num, line in zip(numbers, my_list) if num >= my_value]
minima = sorted(minima, key=lambda x: x[0])
top3 = [val[1] for val in minima[:3]]
print(top3)
 

Сначала я создаю список numbers , который содержит значения индекса 2 каждого списка в my_list преобразованном виде с плавающей точкой, поэтому мы действительно можем выполнять вычисления с этими числами. Это делается с использованием понимания списка.

Затем я создаю новый список minima , в котором я вычисляю разницу между my_value и всеми значениями numbers , с условием, что значение в числах должно быть больше или равно my_number . Используя zip(number, my_list) одновременный цикл как списка numbers , my_list так и для того, чтобы я мог объединить разницу num - myvalue вместе с соответствующим значением в индексе 3 my_list в кортеж.

Затем список minima выглядит следующим образом:

 [(2.0, '0,15'),
 (1.9000000000000057, '0,32'),
 (1.3799999999999955, '0,44'),
 (0.9399999999999977, '0,60'),
 (0.4900000000000091, '0,78'),
 (2.759999999999991, '0,10'),
 (2.1599999999999966, '0,20'),
 (1.5600000000000023, '0,35'),
 (1.009999999999991, '0,40'),
 (0.12999999999999545, '0,75'),
 (2.1999999999999886, '0,11'),
 (2.0999999999999943, '0,31'),
 (1.3199999999999932, '0,45'),
 (0.6100000000000136, '0,67'),
 (0.009999999999990905, '0,72')]
 

Затем я сортирую этот список в порядке возрастания по его первому значению в кортеже, которое является разницей между my_value и числами в индексе 3. Затем я беру первые три и возвращаю только второе значение в кортеже.

Просто в качестве примечания: если вы имеете дело с табличными данными, подобными этому, было бы неплохо заглянуть в библиотеку pandas. Другой ответ на этот пост показывает способ сделать это с помощью pandas. С помощью этой библиотеки часто бывает проще и удобнее работать с табличными данными, поскольку она предлагает множество функциональных возможностей для простого выполнения большого количества операций с данными и анализа.

Комментарии:

1. Ваш top3 выдает правильный вывод. Можете ли вы дать подробное объяснение того, что вы на самом деле сделали?

2. Я отредактировал свой пост с объяснением.

3. @TangerCity Вы уверены, что это дает правильную перестройку? Кажется, что это только случайно дает правильный результат, потому что значения находятся в одинаковом диапазоне для каждой страны.

4. О, возможно, я действительно неправильно понял вопрос. Вероятно, это правда, что это не всегда даст правильный результат, поскольку я не группирую по странам. Извините за это.

5. @sunnytown Как вы добавляете эту группировку по странам?

Ответ №3:

Почему бы не использовать встроенную функцию сортировки()?:

 
my_list = [row for row in my_list if float(row[2].replace(',','.')) >= my_value]
my_list.sort(key=lambda l:float(l[2].replace(',','.')))

for row in my_list:
    print(row)
 

>

 ['Italy', 'Meat', '188,01', '0,72']
['Spain', 'Meat', '188,13', '0,75']
['Morocco', 'Meat', '188,49', '0,78']
['Italy', 'Meat', '188,61', '0,67']
['Morocco', 'Meat', '188,94', '0,60']
['Spain', 'Meat', '189,01', '0,40']
['Italy', 'Meat', '189,32', '0,45']
['Morocco', 'Meat', '189,38', '0,44']
['Spain', 'Meat', '189,56', '0,35']
['Morocco', 'Meat', '189,90', '0,32']
['Morocco', 'Meat', '190,00', '0,15']
['Italy', 'Meat', '190,10', '0,31']
['Spain', 'Meat', '190,16', '0,20']
['Italy', 'Meat', '190,20', '0,11']
['Spain', 'Meat', '190,76', '0,10']