Самый питонический способ создания списка/генератора с ограничениями

Я хотел бы построить функцию в matplotlib, но только в диапазоне, ограниченном двумя числами с плавающей запятой, скажем 2.6 и 8.2. Для этого мне нужен список или генератор, который включает в себя две границы с плавающей запятой, например

[2.6, 3, 4, 5, 6, 7, 8, 8.2]

Я знаю, что это можно сделать вот так

lst = [2.6]
lst.extend(list(range(ceil(2.6), ceil(8.2))))
lst.append(8.2)

но это очень необычно. Есть ли лучший питонический способ сделать это?

Если границы 0.0 и 10.0, каким должен быть результат? Должен ли вывод начинаться с [0.0, 0, [0.0, 1 или чего-то еще? Должно ли оно заканчиваться на 9, 10.0], 10, 10.0], 9] или на что-то еще?

user2357112 25.04.2024 12:20

Ваши требования необычны, поэтому, возможно, следует ожидать необычного решения.

John Coleman 25.04.2024 12:22

@JohnColeman Возможно, ты прав. То, что мне на самом деле нужно, на самом деле не так уж и странно - я хочу построить функцию в matplotlib, но только в определенном диапазоне с плавающей запятой.

Pygmalion 25.04.2024 12:30

@ user2357112 Я отредактировал вопрос, чтобы прояснить мои требования.

Pygmalion 25.04.2024 12:33

Если вам это нужно для построения графиков, то почему вас волнует, являются ли промежуточные точки целыми числами? Не было бы разумнее иметь точки, расположенные на равном расстоянии друг от друга?

John Coleman 25.04.2024 12:34

Вы можете написать это как lst = [2.6, *range(floor(2.6) + 1, ceil(8.2)), 8.2] и заменить числа переменными. Однако ошибки округления могут привести к неверным результатам.

Michael Butscher 25.04.2024 12:35

Ваши требования вообще не ясны. Поскольку, похоже, у вас есть рабочий пример, можете ли вы включить минимально воспроизводимый пример с сюжетом в ваш вопрос? plt.xlim(2.6, 8.2) может быть всем, что вам нужно, если вы используете range(10) для своих значений x.

Joooeey 25.04.2024 12:36

@JohnColeman На самом деле эти диапазоны имеют разную длину, поэтому количество точек зависит от диапазона. Кроме того, поскольку я рисую дважды (один раз для всего диапазона черным цветом и один раз только для указанного диапазона другим цветом), было бы хорошо, чтобы точки рисования для этих двух графиков совпадали.

Pygmalion 25.04.2024 12:39
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
8
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Дополнительные обобщения распаковки PEP 448 делают это хотя бы немного менее многословным:

lst = [2.6, *range(ceil(2.6), ceil(8.2)), 8.2]

Я бы лично обернул его в функцию и задокументировал, что/почему вы это делаете, но он отлично работает в виде встроенного кода, если предположить, что код имеет больше смысла в контексте, чем отсутствие контекста здесь.

Если ленивая генерация (один проход, отсутствие сбора в памяти) приемлема/желательна, вы можете использовать itertools.chain, чтобы создать итератор, производящий те же значения:

from itertools import chain

gen = chain([2.6], range(ceil(2.6), ceil(8.2)), [8.2])

Если предоставляемые значения сами могут быть четными целыми числами, вы можете использовать math.nextafter, чтобы гарантировать, что границы range не перекрывают начальную точку, изменив range на:

range(ceil(math.nextafter(2.6, math.inf)), ceil(8.2))

для любого решения выше.


Кстати, вызов list в исходном коде был избыточным; .extend принимает любую итерацию, как и конструктор list, поэтому, если вы можете сначала преобразовать его в list, вы можете передать его extend напрямую и избежать временного list.

Это ленивая генерация, но я предпочитаю простоту кода экономии памяти (если только речь не идет об огромных списках).

Pygmalion 25.04.2024 12:53
nextafter кажется сложнее, чем floor(2.6) + 1.
no comment 25.04.2024 16:05

@nocomment: Конечно, все, что плывет на вашей лодке. Я чувствовал, что логика nextafter+ceil более точно соответствует логическому замыслу, но, конечно, это работает в любом случае.

ShadowRanger 26.04.2024 00:52

Другие вопросы по теме